From 91cdeeac16fde9f357f43cd5bc4b41d883b331c8 Mon Sep 17 00:00:00 2001 From: siddontang Date: Thu, 5 Mar 2015 15:49:08 +0800 Subject: [PATCH 01/11] scan support sac and desc https://github.com/siddontang/ledisdb/issues/138 --- ledis/scan.go | 226 +++++++++++++++++++++++++++++++-------------- ledis/scan_test.go | 30 ++++++ server/cmd_scan.go | 66 ++++++++++--- 3 files changed, 238 insertions(+), 84 deletions(-) diff --git a/ledis/scan.go b/ledis/scan.go index 466f1ec..cdf18dc 100644 --- a/ledis/scan.go +++ b/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) +} diff --git a/ledis/scan_test.go b/ledis/scan_test.go index 9505964..e7d3171 100644 --- a/ledis/scan_test.go +++ b/ledis/scan_test.go @@ -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)) + } + } diff --git a/server/cmd_scan.go b/server/cmd_scan.go index 1e62d8f..dc579c4 100644 --- a/server/cmd_scan.go +++ b/server/cmd_scan.go @@ -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 } From 62219bbe74f8a9eb290cd0bd4c0496cb205b4e2a Mon Sep 17 00:00:00 2001 From: siddontang Date: Thu, 5 Mar 2015 15:49:15 +0800 Subject: [PATCH 02/11] update doc --- cmd/ledis-cli/const.go | 15 +++++++++------ doc/commands.json | 30 ++++++++++++++++++++++++------ doc/commands.md | 40 +++++++++++++++++++++++++++++----------- 3 files changed, 62 insertions(+), 23 deletions(-) diff --git a/cmd/ledis-cli/const.go b/cmd/ledis-cli/const.go index df18fd6..5404cf4 100644 --- a/cmd/ledis-cli/const.go +++ b/cmd/ledis-cli/const.go @@ -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"}, diff --git a/doc/commands.json b/doc/commands.json index 1ae730a..87ee379 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -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 } } diff --git a/doc/commands.md b/doc/commands.md index a5f33d7..272746f 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -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 From 9dfc4f0e2616dcb36dd13cb7ae700327561a6261 Mon Sep 17 00:00:00 2001 From: siddontang Date: Sat, 7 Mar 2015 08:39:18 +0800 Subject: [PATCH 03/11] remove unnecessary benchmark code --- cmd/ledis-dbbench/main.go | 177 ------------------------------------ cmd/ledis-respbench/main.go | 158 -------------------------------- 2 files changed, 335 deletions(-) delete mode 100644 cmd/ledis-dbbench/main.go delete mode 100644 cmd/ledis-respbench/main.go diff --git a/cmd/ledis-dbbench/main.go b/cmd/ledis-dbbench/main.go deleted file mode 100644 index 0ab8277..0000000 --- a/cmd/ledis-dbbench/main.go +++ /dev/null @@ -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("") - } -} diff --git a/cmd/ledis-respbench/main.go b/cmd/ledis-respbench/main.go deleted file mode 100644 index fcdf239..0000000 --- a/cmd/ledis-respbench/main.go +++ /dev/null @@ -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()) -} From acabb99368f090ff832588163963efd5851afd67 Mon Sep 17 00:00:00 2001 From: siddontang Date: Sat, 7 Mar 2015 10:19:15 +0800 Subject: [PATCH 04/11] move rdb package --- Godeps/Godeps.json | 4 + .../src/github.com/siddontang/rdb/LICENSE | 21 + .../src/github.com/siddontang/rdb/README.md | 3 + .../src/github.com/siddontang}/rdb/decode.go | 6 +- .../src/github.com/siddontang/rdb/digest.go | 106 +++++ .../src/github.com/siddontang}/rdb/encode.go | 2 +- .../src/github.com/siddontang/rdb/loader.go | 112 ++++++ .../github.com/siddontang/rdb/loader_test.go | 373 ++++++++++++++++++ .../github.com/siddontang}/rdb/rdb_test.go | 0 .../src/github.com/siddontang/rdb/reader.go | 332 ++++++++++++++++ .../siddontang}/rdb/wandoujia-license | 0 ledis/migrate.go | 6 +- 12 files changed, 958 insertions(+), 7 deletions(-) create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/LICENSE create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/README.md rename {ledis => Godeps/_workspace/src/github.com/siddontang}/rdb/decode.go (97%) create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/digest.go rename {ledis => Godeps/_workspace/src/github.com/siddontang}/rdb/encode.go (98%) create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/loader.go create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/loader_test.go rename {ledis => Godeps/_workspace/src/github.com/siddontang}/rdb/rdb_test.go (100%) create mode 100644 Godeps/_workspace/src/github.com/siddontang/rdb/reader.go rename {ledis => Godeps/_workspace/src/github.com/siddontang}/rdb/wandoujia-license (100%) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index a52e0e5..eb407f5 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -58,6 +58,10 @@ "ImportPath": "github.com/siddontang/go/sync2", "Rev": "c2b33271306fcb7c6532efceac33ec45ee2439e0" }, + { + "ImportPath": "github.com/siddontang/rdb", + "Rev": "fc89ed2e418d27e3ea76e708e54276d2b44ae9cf" + }, { "ImportPath": "github.com/syndtr/goleveldb/leveldb", "Rev": "e9e2c8f6d3b9c313fb4acaac5ab06285bcf30b04" diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/LICENSE b/Godeps/_workspace/src/github.com/siddontang/rdb/LICENSE new file mode 100644 index 0000000..c16e3af --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/LICENSE @@ -0,0 +1,21 @@ +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. \ No newline at end of file diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/README.md b/Godeps/_workspace/src/github.com/siddontang/rdb/README.md new file mode 100644 index 0000000..aa1582e --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/README.md @@ -0,0 +1,3 @@ +# rdb + +Handling Redis RDB format. diff --git a/ledis/rdb/decode.go b/Godeps/_workspace/src/github.com/siddontang/rdb/decode.go similarity index 97% rename from ledis/rdb/decode.go rename to Godeps/_workspace/src/github.com/siddontang/rdb/decode.go index 06cd392..865d241 100644 --- a/ledis/rdb/decode.go +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/decode.go @@ -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 diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/digest.go b/Godeps/_workspace/src/github.com/siddontang/rdb/digest.go new file mode 100644 index 0000000..b59e4df --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/digest.go @@ -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 } diff --git a/ledis/rdb/encode.go b/Godeps/_workspace/src/github.com/siddontang/rdb/encode.go similarity index 98% rename from ledis/rdb/encode.go rename to Godeps/_workspace/src/github.com/siddontang/rdb/encode.go index 1c33cb0..19c48c3 100644 --- a/ledis/rdb/encode.go +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/encode.go @@ -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))) diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/loader.go b/Godeps/_workspace/src/github.com/siddontang/rdb/loader.go new file mode 100644 index 0000000..22743cb --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/loader.go @@ -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() +} diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/loader_test.go b/Godeps/_workspace/src/github.com/siddontang/rdb/loader_test.go new file mode 100644 index 0000000..db8e2ee --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/loader_test.go @@ -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) + } +} diff --git a/ledis/rdb/rdb_test.go b/Godeps/_workspace/src/github.com/siddontang/rdb/rdb_test.go similarity index 100% rename from ledis/rdb/rdb_test.go rename to Godeps/_workspace/src/github.com/siddontang/rdb/rdb_test.go diff --git a/Godeps/_workspace/src/github.com/siddontang/rdb/reader.go b/Godeps/_workspace/src/github.com/siddontang/rdb/reader.go new file mode 100644 index 0000000..89ae9ed --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/rdb/reader.go @@ -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 +} diff --git a/ledis/rdb/wandoujia-license b/Godeps/_workspace/src/github.com/siddontang/rdb/wandoujia-license similarity index 100% rename from ledis/rdb/wandoujia-license rename to Godeps/_workspace/src/github.com/siddontang/rdb/wandoujia-license diff --git a/ledis/migrate.go b/ledis/migrate.go index b6df026..0db22b4 100644 --- a/ledis/migrate.go +++ b/ledis/migrate.go @@ -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 From c6c82b979d87b7ae56639a4f5ba9367f38bf4922 Mon Sep 17 00:00:00 2001 From: siddontang Date: Sat, 7 Mar 2015 12:47:35 +0800 Subject: [PATCH 05/11] Use key lock when migration https://github.com/siddontang/ledisdb/issues/141 Now migration is only safe for xcodis, but I think it does not matter. --- server/app.go | 6 +- server/cmd_migrate.go | 164 ++++++++++++++++++++++++++++++------------ server/const.go | 8 +++ 3 files changed, 131 insertions(+), 47 deletions(-) diff --git a/server/app.go b/server/app.go index 12ef2d7..4917afc 100644 --- a/server/app.go +++ b/server/app.go @@ -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]*goledis.Client + migrateKeyLockers map[string]*migrateKeyLocker } func netType(s string) string { @@ -76,6 +77,7 @@ func NewApp(cfg *config.Config) (*App, error) { app.rcs = make(map[*respClient]struct{}) app.migrateClients = make(map[string]*goledis.Client) + app.newMigrateKeyLockers() var err error diff --git a/server/cmd_migrate.go b/server/cmd_migrate.go index ffe47c7..51430d4 100644 --- a/server/cmd_migrate.go +++ b/server/cmd_migrate.go @@ -2,10 +2,13 @@ package server import ( "fmt" + "strings" + "sync" + "time" + + "github.com/siddontang/go/hack" goledis "github.com/siddontang/ledisdb/client/goledis" "github.com/siddontang/ledisdb/ledis" - "strings" - "time" ) func dumpCommand(c *client) error { @@ -110,15 +113,15 @@ 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 +132,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 +150,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 +167,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 +188,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 { @@ -211,6 +214,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 +292,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 { @@ -250,13 +315,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 { @@ -270,6 +329,7 @@ func xmigratedbCommand(c *client) error { if err != nil { return err } + defer conn.Close() //timeout is milliseconds t := time.Duration(timeout) * time.Millisecond @@ -278,13 +338,24 @@ func xmigratedbCommand(c *client) error { return err } + migrateNum := int64(0) for _, key := range keys { - data, err := xdump(m.DB, tp, key) - if err != nil { - return err + if !c.app.migrateKeyLock(tp, key) { + // other may also migrate this key, skip it + continue } - ttl, err := xttl(m.DB, tp, key) + defer c.app.migrateKeyUnlock(tp, key) + + data, err := xdump(c.db, tp, key) + if err != nil { + return err + } else if data == nil { + // no key now, skip it + continue + } + + ttl, err := xttl(c.db, tp, key) if err != nil { return err } @@ -296,13 +367,14 @@ func xmigratedbCommand(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 } + migrateNum++ } - c.resp.writeInteger(int64(len(keys))) + c.resp.writeInteger(migrateNum) return nil } @@ -323,7 +395,7 @@ 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) if err != nil { @@ -339,13 +411,14 @@ func xmigrateCommand(c *client) error { return fmt.Errorf("invalid timeout %d", timeout) } - m, err := c.db.Multi() - if err != nil { - return err + if !c.app.migrateKeyLock(tp, key) { + // other may also migrate this key, skip it + return fmt.Errorf("%s %s is in migrating yet", tp, key) } - defer m.Close() - data, err := xdump(m.DB, tp, key) + defer c.app.migrateKeyUnlock(tp, key) + + data, err := xdump(c.db, tp, key) if err != nil { return err } else if data == nil { @@ -353,7 +426,7 @@ func xmigrateCommand(c *client) error { return nil } - ttl, err := xttl(m.DB, tp, key) + ttl, err := xttl(c.db, tp, key) if err != nil { return err } @@ -364,6 +437,7 @@ func xmigrateCommand(c *client) error { if err != nil { return err } + defer conn.Close() //timeout is milliseconds t := time.Duration(timeout) * time.Millisecond @@ -379,7 +453,7 @@ 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 } diff --git a/server/const.go b/server/const.go index 9804ad7..4d72743 100644 --- a/server/const.go +++ b/server/const.go @@ -34,6 +34,14 @@ 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 From 4eeaffbc00417258f732a13f2fb9a5b1b7254f82 Mon Sep 17 00:00:00 2001 From: siddontang Date: Sat, 7 Mar 2015 16:51:27 +0800 Subject: [PATCH 06/11] simplify migration code handle ALL for xmigrate type --- server/cmd_migrate.go | 145 ++++++++++++++++++++++--------------- server/cmd_migrate_test.go | 15 ++++ server/const.go | 2 + 3 files changed, 102 insertions(+), 60 deletions(-) diff --git a/server/cmd_migrate.go b/server/cmd_migrate.go index 51430d4..c3233de 100644 --- a/server/cmd_migrate.go +++ b/server/cmd_migrate.go @@ -1,6 +1,7 @@ package server import ( + "errors" "fmt" "strings" "sync" @@ -301,11 +302,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) @@ -323,52 +322,21 @@ 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 { - if !c.app.migrateKeyLock(tp, key) { - // other may also migrate this key, skip it - continue - } - - defer c.app.migrateKeyUnlock(tp, key) - - data, err := xdump(c.db, tp, key) + err = migrateKey(c, conn, tp, key, timeout) if err != nil { - return err - } else if data == nil { - // no key now, skip it - continue - } - - ttl, err := xttl(c.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(c.db, tp, key); err != nil { - return err + if err == errNoKey || err == errKeyInMigrating { + continue + } else { + return err + } } migrateNum++ @@ -379,6 +347,16 @@ func xmigratedbCommand(c *client) error { 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 @@ -397,11 +375,9 @@ func xmigrateCommand(c *client) error { 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) @@ -411,9 +387,57 @@ func xmigrateCommand(c *client) error { return fmt.Errorf("invalid timeout %d", timeout) } + conn, err := getMigrateDBConn(c, addr, db) + if err != nil { + return err + } + defer conn.Close() + + 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 != nil { + 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) (*goledis.Conn, 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 *goledis.Conn, tp string, key []byte, timeout int64) error { if !c.app.migrateKeyLock(tp, key) { // other may also migrate this key, skip it - return fmt.Errorf("%s %s is in migrating yet", tp, key) + return errKeyInMigrating } defer c.app.migrateKeyUnlock(tp, key) @@ -422,8 +446,7 @@ func xmigrateCommand(c *client) error { if err != nil { return err } else if data == nil { - c.resp.writeStatus(NOKEY) - return nil + return errNoKey } ttl, err := xttl(c.db, tp, key) @@ -431,21 +454,9 @@ func xmigrateCommand(c *client) error { return err } - mc := c.app.getMigrateClient(addr) - - conn, err := mc.Get() - 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 - } - conn.SetReadDeadline(time.Now().Add(t)) //ttl is second, but restore need millisecond @@ -457,7 +468,21 @@ func xmigrateCommand(c *client) error { return err } - c.resp.writeStatus(OK) + return nil +} + +func migrateAllTypeKeys(c *client, conn *goledis.Conn, key []byte, timeout int64) error { + for _, tp := range TypeNames { + err := migrateKey(c, conn, tp, key, timeout) + if err != nil { + if err == errNoKey || err == errKeyInMigrating { + continue + } else { + return err + } + } + } + return nil } diff --git a/server/cmd_migrate_test.go b/server/cmd_migrate_test.go index 0bfc6cb..0545676 100644 --- a/server/cmd_migrate_test.go +++ b/server/cmd_migrate_test.go @@ -125,4 +125,19 @@ func TestMigrate(t *testing.T) { 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 := ledis.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 { + t.Fatal(err) + } else if s != "" { + t.Fatal(s, "must empty") + } } diff --git a/server/const.go b/server/const.go index 4d72743..d5c7308 100644 --- a/server/const.go +++ b/server/const.go @@ -47,3 +47,5 @@ const ( MB uint64 = 1024 * 1024 KB uint64 = 1024 ) + +var TypeNames = []string{KVName, ListName, HashName, SetName, ZSetName} From ce8e0d4fdc75d40466f51b5a589e62f6f8ee569a Mon Sep 17 00:00:00 2001 From: siddontang Date: Mon, 9 Mar 2015 10:00:29 +0800 Subject: [PATCH 07/11] retry migration when key is in migrating --- server/cmd_migrate.go | 64 +++++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 14 deletions(-) diff --git a/server/cmd_migrate.go b/server/cmd_migrate.go index c3233de..afc2800 100644 --- a/server/cmd_migrate.go +++ b/server/cmd_migrate.go @@ -8,6 +8,7 @@ import ( "time" "github.com/siddontang/go/hack" + "github.com/siddontang/go/log" goledis "github.com/siddontang/ledisdb/client/goledis" "github.com/siddontang/ledisdb/ledis" ) @@ -110,6 +111,29 @@ 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 @@ -393,19 +417,30 @@ func xmigrateCommand(c *client) error { } defer conn.Close() - 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 != nil { - if err == errNoKey { - c.resp.writeStatus(NOKEY) - return nil - } else { - return err - } + // 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) + } + } + + if err != nil { + if err == errNoKey { + c.resp.writeStatus(NOKEY) + return nil + } else { + return err } } @@ -475,7 +510,7 @@ func migrateAllTypeKeys(c *client, conn *goledis.Conn, key []byte, timeout int64 for _, tp := range TypeNames { err := migrateKey(c, conn, tp, key, timeout) if err != nil { - if err == errNoKey || err == errKeyInMigrating { + if err == errNoKey { continue } else { return err @@ -493,6 +528,7 @@ func init() { register("sdump", sdumpCommand) register("zdump", zdumpCommand) register("restore", restoreCommand) + register("xrestore", xrestoreCommand) register("xdump", xdumpCommand) register("xmigrate", xmigrateCommand) register("xmigratedb", xmigratedbCommand) From 186ed2f84fb1152869da48f74fd0a2227b45dba9 Mon Sep 17 00:00:00 2001 From: siddontang Date: Wed, 11 Mar 2015 11:54:02 +0800 Subject: [PATCH 08/11] use goredis client --- Godeps/Godeps.json | 6 +- .../github.com/siddontang/goredis}/LICENSE | 5 +- .../github.com/siddontang/goredis}/client.go | 77 ++++++--- .../github.com/siddontang/goredis}/conn.go | 83 ++++++---- .../src/github.com/siddontang/goredis/doc.go | 34 ++++ .../siddontang/goredis}/garyburd_license | 0 .../siddontang/goredis/goredis_test.go | 39 +++++ .../github.com/siddontang/goredis}/reply.go | 26 +-- bootstrap.sh | 2 + client/README.md | 1 - client/goledis/doc.go | 45 ------ client/goledis/ledis_test.go | 15 -- cmd/ledis-benchmark/main.go | 58 ++++--- cmd/ledis-cli/main.go | 21 ++- cmd/ledis-dump/main.go | 4 +- server/app.go | 6 +- server/app_test.go | 12 +- server/cmd_bit_test.go | 54 +++---- server/cmd_hash_test.go | 56 +++---- server/cmd_kv_test.go | 60 +++---- server/cmd_list_test.go | 42 ++--- server/cmd_migrate.go | 13 +- server/cmd_migrate_test.go | 24 +-- server/cmd_replication_test.go | 6 +- server/cmd_scan_test.go | 32 ++-- server/cmd_script_test.go | 16 +- server/cmd_set_test.go | 34 ++-- server/cmd_sort_test.go | 4 +- server/cmd_ttl_test.go | 22 +-- server/cmd_zset_test.go | 152 +++++++++--------- server/replication.go | 8 +- 31 files changed, 504 insertions(+), 453 deletions(-) rename {client => Godeps/_workspace/src/github.com/siddontang/goredis}/LICENSE (96%) rename {client/goledis => Godeps/_workspace/src/github.com/siddontang/goredis}/client.go (55%) rename {client/goledis => Godeps/_workspace/src/github.com/siddontang/goredis}/conn.go (80%) create mode 100644 Godeps/_workspace/src/github.com/siddontang/goredis/doc.go rename {client/goledis => Godeps/_workspace/src/github.com/siddontang/goredis}/garyburd_license (100%) create mode 100644 Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go rename {client/goledis => Godeps/_workspace/src/github.com/siddontang/goredis}/reply.go (86%) delete mode 100644 client/README.md delete mode 100644 client/goledis/doc.go delete mode 100644 client/goledis/ledis_test.go diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index eb407f5..b572bdd 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,6 +1,6 @@ { "ImportPath": "github.com/siddontang/ledisdb", - "GoVersion": "go1.4", + "GoVersion": "go1.4.2", "Packages": [ "./..." ], @@ -58,6 +58,10 @@ "ImportPath": "github.com/siddontang/go/sync2", "Rev": "c2b33271306fcb7c6532efceac33ec45ee2439e0" }, + { + "ImportPath": "github.com/siddontang/goredis", + "Rev": "6d2857b0488d1e8b9f96b46802eacb68e29fb003" + }, { "ImportPath": "github.com/siddontang/rdb", "Rev": "fc89ed2e418d27e3ea76e708e54276d2b44ae9cf" diff --git a/client/LICENSE b/Godeps/_workspace/src/github.com/siddontang/goredis/LICENSE similarity index 96% rename from client/LICENSE rename to Godeps/_workspace/src/github.com/siddontang/goredis/LICENSE index 7ece9fd..cc485b0 100644 --- a/client/LICENSE +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/LICENSE @@ -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 @@ -18,4 +18,5 @@ 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. \ No newline at end of file +SOFTWARE. + diff --git a/client/goledis/client.go b/Godeps/_workspace/src/github.com/siddontang/goredis/client.go similarity index 55% rename from client/goledis/client.go rename to Godeps/_workspace/src/github.com/siddontang/goredis/client.go index a6811f4..e535fea 100644 --- a/client/goledis/client.go +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/client.go @@ -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() diff --git a/client/goledis/conn.go b/Godeps/_workspace/src/github.com/siddontang/goredis/conn.go similarity index 80% rename from client/goledis/conn.go rename to Godeps/_workspace/src/github.com/siddontang/goredis/conn.go index d78bc03..a13d620 100644 --- a/client/goledis/conn.go +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/conn.go @@ -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 } diff --git a/Godeps/_workspace/src/github.com/siddontang/goredis/doc.go b/Godeps/_workspace/src/github.com/siddontang/goredis/doc.go new file mode 100644 index 0000000..db93820 --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/doc.go @@ -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 diff --git a/client/goledis/garyburd_license b/Godeps/_workspace/src/github.com/siddontang/goredis/garyburd_license similarity index 100% rename from client/goledis/garyburd_license rename to Godeps/_workspace/src/github.com/siddontang/goredis/garyburd_license diff --git a/Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go b/Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go new file mode 100644 index 0000000..f96efcb --- /dev/null +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/goredis_test.go @@ -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) + } +} diff --git a/client/goledis/reply.go b/Godeps/_workspace/src/github.com/siddontang/goredis/reply.go similarity index 86% rename from client/goledis/reply.go rename to Godeps/_workspace/src/github.com/siddontang/goredis/reply.go index e9e8993..f2c6f17 100644 --- a/client/goledis/reply.go +++ b/Godeps/_workspace/src/github.com/siddontang/goredis/reply.go @@ -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) } diff --git a/bootstrap.sh b/bootstrap.sh index 9133b6a..02bc20a 100755 --- a/bootstrap.sh +++ b/bootstrap.sh @@ -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 diff --git a/client/README.md b/client/README.md deleted file mode 100644 index ef54008..0000000 --- a/client/README.md +++ /dev/null @@ -1 +0,0 @@ -[Clients](https://github.com/siddontang/ledisdb/wiki/Clients) \ No newline at end of file diff --git a/client/goledis/doc.go b/client/goledis/doc.go deleted file mode 100644 index 05ee2a0..0000000 --- a/client/goledis/doc.go +++ /dev/null @@ -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 diff --git a/client/goledis/ledis_test.go b/client/goledis/ledis_test.go deleted file mode 100644 index 6582d04..0000000 --- a/client/goledis/ledis_test.go +++ /dev/null @@ -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() -} diff --git a/cmd/ledis-benchmark/main.go b/cmd/ledis-benchmark/main.go index 2c861c9..918c7e4 100644 --- a/cmd/ledis-benchmark/main.go +++ b/cmd/ledis-benchmark/main.go @@ -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() diff --git a/cmd/ledis-cli/main.go b/cmd/ledis-cli/main.go index e66fc11..38097a6 100644 --- a/cmd/ledis-cli/main.go +++ b/cmd/ledis-cli/main.go @@ -3,7 +3,7 @@ package main import ( "flag" "fmt" - "github.com/siddontang/ledisdb/client/goledis" + "github.com/siddontang/goredis" "regexp" "strconv" "strings" @@ -17,16 +17,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 +37,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 +101,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 +153,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") diff --git a/cmd/ledis-dump/main.go b/cmd/ledis-dump/main.go index b6dd99e..7ecaffa 100644 --- a/cmd/ledis-dump/main.go +++ b/cmd/ledis-dump/main.go @@ -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 diff --git a/server/app.go b/server/app.go index 4917afc..ad4f6ba 100644 --- a/server/app.go +++ b/server/app.go @@ -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" @@ -45,7 +45,7 @@ type App struct { rcs map[*respClient]struct{} migrateM sync.Mutex - migrateClients map[string]*goledis.Client + migrateClients map[string]*goredis.Client migrateKeyLockers map[string]*migrateKeyLocker } @@ -76,7 +76,7 @@ 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 diff --git a/server/app_test.go b/server/app_test.go index 3a23538..6347cbc 100644 --- a/server/app_test.go +++ b/server/app_test.go @@ -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 diff --git a/server/cmd_bit_test.go b/server/cmd_bit_test.go index f6344c4..f67e0aa 100644 --- a/server/cmd_bit_test.go +++ b/server/cmd_bit_test.go @@ -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) // } diff --git a/server/cmd_hash_test.go b/server/cmd_hash_test.go index c9bbd77..847597a 100644 --- a/server/cmd_hash_test.go +++ b/server/cmd_hash_test.go @@ -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) diff --git a/server/cmd_kv_test.go b/server/cmd_kv_test.go index b4497f9..a196155 100644 --- a/server/cmd_kv_test.go +++ b/server/cmd_kv_test.go @@ -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) diff --git a/server/cmd_list_test.go b/server/cmd_list_test.go index 5a237fc..66f1a75 100644 --- a/server/cmd_list_test.go +++ b/server/cmd_list_test.go @@ -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) diff --git a/server/cmd_migrate.go b/server/cmd_migrate.go index afc2800..edc52e3 100644 --- a/server/cmd_migrate.go +++ b/server/cmd_migrate.go @@ -9,7 +9,7 @@ import ( "github.com/siddontang/go/hack" "github.com/siddontang/go/log" - goledis "github.com/siddontang/ledisdb/client/goledis" + "github.com/siddontang/goredis" "github.com/siddontang/ledisdb/ledis" ) @@ -224,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() @@ -448,7 +447,7 @@ func xmigrateCommand(c *client) error { return nil } -func getMigrateDBConn(c *client, addr string, db uint64) (*goledis.Conn, error) { +func getMigrateDBConn(c *client, addr string, db uint64) (*goredis.PoolConn, error) { mc := c.app.getMigrateClient(addr) conn, err := mc.Get() @@ -469,7 +468,7 @@ var ( errKeyInMigrating = errors.New("key is in migrating yet") ) -func migrateKey(c *client, conn *goledis.Conn, tp string, key []byte, timeout int64) error { +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 @@ -506,7 +505,7 @@ func migrateKey(c *client, conn *goledis.Conn, tp string, key []byte, timeout in return nil } -func migrateAllTypeKeys(c *client, conn *goledis.Conn, key []byte, timeout int64) error { +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 { diff --git a/server/cmd_migrate_test.go b/server/cmd_migrate_test.go index 0545676..45dcea1 100644 --- a/server/cmd_migrate_test.go +++ b/server/cmd_migrate_test.go @@ -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,31 +95,31 @@ 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") @@ -129,13 +129,13 @@ 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") diff --git a/server/cmd_replication_test.go b/server/cmd_replication_test.go index f4c13fc..c614122 100644 --- a/server/cmd_replication_test.go +++ b/server/cmd_replication_test.go @@ -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) { diff --git a/server/cmd_scan_test.go b/server/cmd_scan_test.go index 328ecad..a5c634c 100644 --- a/server/cmd_scan_test.go +++ b/server/cmd_scan_test.go @@ -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)) diff --git a/server/cmd_script_test.go b/server/cmd_script_test.go index 88758fd..56f8cec 100644 --- a/server/cmd_script_test.go +++ b/server/cmd_script_test.go @@ -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)) diff --git a/server/cmd_set_test.go b/server/cmd_set_test.go index 2680c81..2846779 100644 --- a/server/cmd_set_test.go +++ b/server/cmd_set_test.go @@ -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) diff --git a/server/cmd_sort_test.go b/server/cmd_sort_test.go index d70dc05..ea5948d 100644 --- a/server/cmd_sort_test.go +++ b/server/cmd_sort_test.go @@ -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) diff --git a/server/cmd_ttl_test.go b/server/cmd_ttl_test.go index 0b4d161..0630ca2 100644 --- a/server/cmd_ttl_test.go +++ b/server/cmd_ttl_test.go @@ -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) diff --git a/server/cmd_zset_test.go b/server/cmd_zset_test.go index fbb9a80..68d7fa7 100644 --- a/server/cmd_zset_test.go +++ b/server/cmd_zset_test.go @@ -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) diff --git a/server/replication.go b/server/replication.go index 8663203..2747e14 100644 --- a/server/replication.go +++ b/server/replication.go @@ -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) From 5f0c295dd590d218b401943a29536bf838f3eee9 Mon Sep 17 00:00:00 2001 From: siddontang Date: Wed, 11 Mar 2015 11:54:16 +0800 Subject: [PATCH 09/11] customize building with lmdv --- Makefile | 6 ++++++ store/mdb/mdb.go | 2 +- store/mdb/snapshot.go | 2 +- store/mdb/tx.go | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index d3b1941..55afc4e 100644 --- a/Makefile +++ b/Makefile @@ -16,12 +16,18 @@ all: build build: $(GO) install -tags '$(GO_BUILD_TAGS)' ./... +build_use_lmdb: + $(GO) install -tags '$(GO_BUILD_TAGS) lmdb' ./... + clean: $(GO) clean -i ./... 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 diff --git a/store/mdb/mdb.go b/store/mdb/mdb.go index 6bf26f6..db27b33 100644 --- a/store/mdb/mdb.go +++ b/store/mdb/mdb.go @@ -1,4 +1,4 @@ -// +build !windows +// +build lmdb package mdb diff --git a/store/mdb/snapshot.go b/store/mdb/snapshot.go index 270907d..0882cd6 100644 --- a/store/mdb/snapshot.go +++ b/store/mdb/snapshot.go @@ -1,4 +1,4 @@ -// +build !windows +// +build lmdb package mdb diff --git a/store/mdb/tx.go b/store/mdb/tx.go index e2e3be0..a4fc01b 100644 --- a/store/mdb/tx.go +++ b/store/mdb/tx.go @@ -1,4 +1,4 @@ -// +build !windows +// +build lmdb package mdb From 2d113aa9be802ee5d5110268e0d097d463d016c3 Mon Sep 17 00:00:00 2001 From: siddontang Date: Thu, 12 Mar 2015 11:32:33 +0800 Subject: [PATCH 10/11] add linenoise build tag avoid some cgo compiling problem --- .gitignore | 3 ++- Makefile | 12 ++++++------ cmd/ledis-cli/complietion.go | 16 ++++++++++++++++ cmd/ledis-cli/const.go | 2 +- cmd/ledis-cli/linenoise.c | 2 ++ cmd/ledis-cli/linenoise.go | 17 ++--------------- cmd/ledis-cli/linenoise.h | 2 ++ cmd/ledis-cli/linenoiseCompletionCallbackHook.c | 1 + cmd/ledis-cli/linenoiseCompletionCallbackHook.h | 1 + cmd/ledis-cli/main.go | 2 ++ cmd/ledis-cli/nolinenoise.go | 7 +++++++ 11 files changed, 42 insertions(+), 23 deletions(-) create mode 100644 cmd/ledis-cli/complietion.go create mode 100644 cmd/ledis-cli/nolinenoise.go diff --git a/.gitignore b/.gitignore index ca83d7c..25f2ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ build nohup.out build_config.mk var* -*.log \ No newline at end of file +*.log +bin \ No newline at end of file diff --git a/Makefile b/Makefile index 55afc4e..3c240de 100644 --- a/Makefile +++ b/Makefile @@ -14,14 +14,11 @@ export GO_BUILD_TAGS all: build build: - $(GO) install -tags '$(GO_BUILD_TAGS)' ./... + $(GO) install -tags 'linenoise $(GO_BUILD_TAGS)' ./... build_use_lmdb: - $(GO) install -tags '$(GO_BUILD_TAGS) lmdb' ./... - -clean: - $(GO) clean -i ./... - + $(GO) install -tags 'linenoise $(GO_BUILD_TAGS) lmdb' ./... + test: $(GO) test --race -tags '$(GO_BUILD_TAGS)' ./... @@ -40,5 +37,8 @@ test_store: test_rpl: $(GO) test --race -tags '$(GO_BUILD_TAGS)' ./rpl +clean: + $(GO) clean -i ./... + fmt: go fmt ./... \ No newline at end of file diff --git a/cmd/ledis-cli/complietion.go b/cmd/ledis-cli/complietion.go new file mode 100644 index 0000000..381ac86 --- /dev/null +++ b/cmd/ledis-cli/complietion.go @@ -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 +} diff --git a/cmd/ledis-cli/const.go b/cmd/ledis-cli/const.go index 5404cf4..cc3f4d9 100644 --- a/cmd/ledis-cli/const.go +++ b/cmd/ledis-cli/const.go @@ -1,4 +1,4 @@ -//This file was generated by .tools/generate_commands.py on Thu Mar 05 2015 15:42:49 +0800 +//This file was generated by .tools/generate_commands.py on Thu Mar 05 2015 15:42:49 +0800 package main var helpCommands = [][]string{ diff --git a/cmd/ledis-cli/linenoise.c b/cmd/ledis-cli/linenoise.c index aef5cdd..e5784d4 100644 --- a/cmd/ledis-cli/linenoise.c +++ b/cmd/ledis-cli/linenoise.c @@ -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. * diff --git a/cmd/ledis-cli/linenoise.go b/cmd/ledis-cli/linenoise.go index 4bb49af..b872b18 100644 --- a/cmd/ledis-cli/linenoise.go +++ b/cmd/ledis-cli/linenoise.go @@ -1,3 +1,5 @@ +// +build linenoise + package main //#include @@ -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; diff --git a/cmd/ledis-cli/linenoise.h b/cmd/ledis-cli/linenoise.h index e22ebd3..fca81f0 100644 --- a/cmd/ledis-cli/linenoise.h +++ b/cmd/ledis-cli/linenoise.h @@ -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. * diff --git a/cmd/ledis-cli/linenoiseCompletionCallbackHook.c b/cmd/ledis-cli/linenoiseCompletionCallbackHook.c index 7561d22..08384fe 100644 --- a/cmd/ledis-cli/linenoiseCompletionCallbackHook.c +++ b/cmd/ledis-cli/linenoiseCompletionCallbackHook.c @@ -1,3 +1,4 @@ +// +build linenoise #include "linenoiseCompletionCallbackHook.h" diff --git a/cmd/ledis-cli/linenoiseCompletionCallbackHook.h b/cmd/ledis-cli/linenoiseCompletionCallbackHook.h index 071170c..fc59e2c 100644 --- a/cmd/ledis-cli/linenoiseCompletionCallbackHook.h +++ b/cmd/ledis-cli/linenoiseCompletionCallbackHook.h @@ -1,3 +1,4 @@ +// +build linenoise #include #include "linenoise.h" diff --git a/cmd/ledis-cli/main.go b/cmd/ledis-cli/main.go index 38097a6..164d8ba 100644 --- a/cmd/ledis-cli/main.go +++ b/cmd/ledis-cli/main.go @@ -1,3 +1,5 @@ +// +build linenoise + package main import ( diff --git a/cmd/ledis-cli/nolinenoise.go b/cmd/ledis-cli/nolinenoise.go new file mode 100644 index 0000000..55d7bc1 --- /dev/null +++ b/cmd/ledis-cli/nolinenoise.go @@ -0,0 +1,7 @@ +// +build !linenoise + +package main + +func main() { + println("Please use linenoise to build again, or use redis-cli instead") +} From ef8d5f7b69ade90458d7ed84f1b5834147ef9f50 Mon Sep 17 00:00:00 2001 From: siddontang Date: Thu, 12 Mar 2015 11:38:21 +0800 Subject: [PATCH 11/11] add warn log for transaction --- ledis/tx.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ledis/tx.go b/ledis/tx.go index 7c13ba4..0403c0f 100644 --- a/ledis/tx.go +++ b/ledis/tx.go @@ -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 }