diff --git a/cmd/ledis-cli/const.go b/cmd/ledis-cli/const.go index a3e0674..9fc72dd 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 Fri Feb 06 2015 09:15:18 +0800 +//This file was generated by .tools/generate_commands.py on Mon Mar 02 2015 14:43:25 +0800 package main var helpCommands = [][]string{ @@ -20,8 +20,6 @@ var helpCommands = [][]string{ {"BRPOP", "key [key ...] timeout", "List"}, {"BSETBIT", "key offset value", "Bitmap"}, {"BTTL", "key", "Bitmap"}, - {"BXREVSCAN", "key [MATCH match] [COUNT count]", "Bitmap"}, - {"BXSCAN", "key [MATCH match] [COUNT count]", "Bitmap"}, {"COMMIT", "-", "Transaction"}, {"CONFIG REWRITE", "-", "Server"}, {"DECR", "key", "KV"}, @@ -59,8 +57,6 @@ var helpCommands = [][]string{ {"HSET", "key field value", "Hash"}, {"HTTL", "key", "Hash"}, {"HVALS", "key", "Hash"}, - {"HXREVSCAN", "key [MATCH match] [COUNT count]", "Hash"}, - {"HXSCAN", "key [MATCH match] [COUNT count]", "Hash"}, {"INCR", "key", "KV"}, {"INCRBY", "key increment", "KV"}, {"INFO", "[section]", "Server"}, @@ -76,8 +72,6 @@ var helpCommands = [][]string{ {"LPUSH", "key value [value ...]", "List"}, {"LRANGE", "key start stop", "List"}, {"LTTL", "key", "List"}, - {"LXREVSCAN", "key [MATCH match] [COUNT count]", "List"}, - {"LXSCAN", "key [MATCH match] [COUNT count]", "List"}, {"MGET", "key [key ...]", "KV"}, {"MSET", "key value [key value ...]", "KV"}, {"PERSIST", "key", "KV"}, @@ -116,23 +110,13 @@ var helpCommands = [][]string{ {"STTL", "key", "Set"}, {"SUNION", "key [key ...]", "Set"}, {"SUNIONSTORE", "destination key [key ...]", "Set"}, - {"SXREVSCAN", "key [MATCH match] [COUNT count]", "Set"}, - {"SXSCAN", "key [MATCH match] [COUNT count]", "Set"}, {"SYNC", "logid", "Replication"}, {"TIME", "-", "Server"}, {"TTL", "key", "KV"}, - {"XBREVSCAN", "key [MATCH match] [COUNT count]", "Bitmap"}, - {"XBSCAN", "key [MATCH match] [COUNT count]", "Bitmap"}, - {"XHREVSCAN", "key [MATCH match] [COUNT count]", "Hash"}, - {"XHSCAN", "key [MATCH match] [COUNT count]", "Hash"}, - {"XLREVSCAN", "key [MATCH match] [COUNT count]", "List"}, - {"XLSCAN", "key [MATCH match] [COUNT count]", "List"}, - {"XREVSCAN", "key [MATCH match] [COUNT count]", "KV"}, - {"XSCAN", "key [MATCH match] [COUNT count]", "KV"}, - {"XSREVSCAN", "key [MATCH match] [COUNT count]", "Set"}, - {"XSSCAN", "key [MATCH match] [COUNT count]", "Set"}, - {"XZREVSCAN", "key [MATCH match] [COUNT count]", "ZSet"}, - {"XZSCAN", "key [MATCH match] [COUNT count]", "ZSet"}, + {"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"}, {"ZADD", "key score member [score member ...]", "ZSet"}, {"ZCARD", "key", "ZSet"}, {"ZCLEAR", "key", "ZSet"}, @@ -159,6 +143,4 @@ var helpCommands = [][]string{ {"ZSCORE", "key member", "ZSet"}, {"ZTTL", "key", "ZSet"}, {"ZUNIONSTORE", "destkey numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]", "ZSet"}, - {"ZXREVSCAN", "key [MATCH match] [COUNT count]", "ZSet"}, - {"ZXSCAN", "key [MATCH match] [COUNT count]", "ZSet"}, } diff --git a/doc/commands.json b/doc/commands.json index 4b549db..281fd07 100644 --- a/doc/commands.json +++ b/doc/commands.json @@ -560,79 +560,7 @@ "group": "Transaction", "readonly": false }, - - "XSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "KV", - "readonly": true - }, - - "HXSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Hash", - "readonly": true - }, - - "LXSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "List", - "readonly": true - }, - - "SXSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Set", - "readonly": true - }, - - "ZXSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "ZSet", - "readonly": true - }, - - "BXSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Bitmap", - "readonly": true - }, - - "XREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "KV", - "readonly": true - }, - - "HXREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Hash", - "readonly": true - }, - - "LXREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "List", - "readonly": true - }, - - "SXREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Set", - "readonly": true - }, - - "ZXREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "ZSet", - "readonly": true - }, - - "BXREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Bitmap", - "readonly": true - }, - + "FLUSHALL": { "arguments": "-", "group": "Server", @@ -724,66 +652,30 @@ "readonly": true }, - "XBSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Bitmap", - "readonly": true - }, - - "XLSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "List", + "XSCAN": { + "arguments": "type cursor [MATCH match] [COUNT count]", + "group": "Server", "readonly": true }, "XHSCAN": { - "arguments": "key [MATCH match] [COUNT count]", + "arguments": "key cursor [MATCH match] [COUNT count]", "group": "Hash", "readonly": true }, "XSSCAN": { - "arguments": "key [MATCH match] [COUNT count]", + "arguments": "key cursor [MATCH match] [COUNT count]", "group": "Set", "readonly": true }, "XZSCAN": { - "arguments": "key [MATCH match] [COUNT count]", + "arguments": "key cursor [MATCH match] [COUNT count]", "group": "ZSet", "readonly": true }, - "XHREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Hash", - "readonly": true - }, - - "XLREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "List", - "readonly": true - }, - - "XSREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Set", - "readonly": true - }, - - "XZREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "ZSet", - "readonly": true - }, - - "XBREVSCAN": { - "arguments": "key [MATCH match] [COUNT count]", - "group": "Bitmap", - "readonly": true - }, - "RESTORE": { "arguments" : "key ttl value", "group" : "Server", diff --git a/doc/commands.md b/doc/commands.md index 1cde082..2e4bce6 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -27,8 +27,6 @@ Table of Contents - [EXPIREAT key timestamp](#expireat-key-timestamp) - [TTL key](#ttl-key) - [PERSIST key](#persist-key) - - [XSCAN key [MATCH match] [COUNT count]](#xscan-key-match-match-count-count) - - [XREVSCAN key [MATCH match] [COUNT count]](#xrevscan-key-match-match-count-count) - [DUMP key](#dump-key) - [Hash](#hash) - [HDEL key field [field ...]](#hdel-key-field-field-) @@ -48,10 +46,6 @@ Table of Contents - [HEXPIREAT key timestamp](#hexpireat-key-timestamp) - [HTTL key](#httl-key) - [HPERSIST key](#hpersist-key) - - [HXSCAN key [MATCH match] [COUNT count]](#hxscan-key-match-match-count-count) - - [HXREVSCAN key [MATCH match] [COUNT count]](#hxrevscan-key-match-match-count-count) - - [XHSCAN key [MATCH match] [COUNT count]](#xhscan-key-match-match-count-count) - - [XHREVSCAN key [MATCH match] [COUNT count]](#xhrevscan-key-match-match-count-count) - [HDUMP key](#hdump-key) - [List](#list) - [BLPOP key [key ...] timeout](#blpop-key-key--timeout) @@ -69,10 +63,6 @@ Table of Contents - [LEXPIREAT key timestamp](#lexpireat-key-timestamp) - [LTTL key](#lttl-key) - [LPERSIST key](#lpersist-key) - - [LXSCAN key [MATCH match] [COUNT count]](#lxscan-key-match-match-count-count) - - [LXREVSCAN key [MATCH match] [COUNT count]](#lxrevscan-key-match-match-count-count) - - [XLSCAN key [MATCH match] [COUNT count]](#xlscan-key-match-match-count-count) - - [XLREVSCAN key [MATCH match] [COUNT count]](#xlrevscan-key-match-match-count-count) - [LDUMP key](#ldump-key) - [Set](#set) - [SADD key member [member ...]](#sadd-key-member-member-) @@ -92,10 +82,6 @@ Table of Contents - [SEXPIREAT key timestamp](#sexpireat-key-timestamp) - [STTL key](#sttl-key) - [SPERSIST key](#spersist-key) - - [SXSCAN key [MATCH match] [COUNT count]](#sxscan-key-match-match-count-count) - - [SXREVSCAN key [MATCH match] [COUNT count]](#sxrevscan-key-match-match-count-count) - - [XSSCAN key [MATCH match] [COUNT count]](#xsscan-key-match-match-count-count) - - [XSREVSCAN key [MATCH match] [COUNT count]](#xsrevscan-key-match-match-count-count) - [SDUMP key](#sdump-key) - [ZSet](#zset) - [ZADD key score member [score member ...]](#zadd-key-score-member-score-member-) @@ -122,10 +108,6 @@ Table of Contents ](#zunionstore-destination-numkeys-key-key--weights-weight-weight--aggregate-summinmax) - [ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] ](#zinterstore-destination-numkeys-key-key--weights-weight-weight--aggregate-summinmax) - - [ZXSCAN key [MATCH match] [COUNT count]](#zxscan-key-match-match-count-count) - - [ZXREVSCAN key [MATCH match] [COUNT count]](#zxrevscan-key-match-match-count-count) - - [XZSCAN key [MATCH match] [COUNT count]](#xzscan-key-match-match-count-count) - - [XZREVSCAN key [MATCH match] [COUNT count]](#xzrevscan-key-match-match-count-count) - [ZRANGEBYLEX key min max [LIMIT offset count]](#zrangebylex-key-min-max-limit-offset-count) - [ZREMRANGEBYLEX key min max](#zremrangebylex-key-min-max) - [ZLEXCOUNT key min max](#zlexcount-key-min-max) @@ -141,10 +123,11 @@ Table of Contents - [BEXPIREAT key timestamp](#bexpireat-key-timestamp) - [BTTL key](#bttl-key) - [BPERSIST key](#bpersist-key) - - [BXSCAN key [MATCH match] [COUNT count]](#bxscan-key-match-match-count-count) - - [BXREVSCAN key [MATCH match] [COUNT count]](#bxrevscan-key-match-match-count-count) - - [XBSCAN key [MATCH match] [COUNT count]](#xbscan-key-match-match-count-count) - - [XBREVSCAN key [MATCH match] [COUNT count]](#xbrevscan-key-match-match-count-count) +- [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) - [Replication](#replication) - [SLAVEOF host port [RESTART] [READONLY]](#slaveof-host-port-restart-readonly) - [FULLSYNC [NEW]](#fullsync-new) @@ -524,82 +507,6 @@ ledis> TTL mykey (integer) -1 ``` -### XSCAN key [MATCH match] [COUNT count] - -Iterate KV keys incrementally. - -Key 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. - -**Return value** - -an array of two values, first value is the key for next iteration, second value is an array of elements. - -**Examples** - -``` -ledis>set a 1 -OK -ledis>set b 2 -OK -ledis>set c 3 -OK -127.0.0.1:6380>xscan "" -1) "" -2) ["a" "b" "c"] -ledis>xscan "" count 1 -1) "a" -2) ["a"] -ledis>xscan "a" count 1 -1) "b" -2) ["b"] -ledis>xscan "b" count 1 -1) "c" -2) ["c"] -ledis>xscan "c" count 1 -1) "" -2) [] -``` - -### XREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate KV keys incrementally. - -Key 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. - -**Return value** - -an array of two values, first value is the key for next iteration, second value is an array of elements. - -**Examples** - -``` -ledis>set a 1 -OK -ledis>set b 2 -OK -ledis>set c 3 -OK -127.0.0.1:6380>xrevscan "" -1) "" -2) ["c" "b" "a"] -ledis>xrevscan "" count 1 -1) "c" -2) ["c"] -ledis>xrevscan "c" count 1 -1) "b" -2) ["b"] -ledis>xrevscan "b" count 1 -1) "a" -2) ["a"] -ledis>xrevscan "a" count 1 -1) "" -2) [] -``` - ### DUMP key Serialize the value stored at key with KV type in a Redis-specific format like RDB and return it to the user. The returned value can be synthesized back into a key using the RESTORE command. @@ -980,31 +887,6 @@ ledis> HPERSIST not_exists_key (integer) 0 ``` -### HXSCAN key [MATCH match] [COUNT count] - -Iterate Hash keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### HXREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate Hash keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - -### XHSCAN key [MATCH match] [COUNT count] - -Iterate Hash keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### XHREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate Hash keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - - ### HDUMP key See [DUMP](#dump-key) for more information. @@ -1331,31 +1213,6 @@ ledis> LPERSIST b (integer) 0 ``` -### LXSCAN key [MATCH match] [COUNT count] - -Iterate list keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### LXREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate list keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - -### XLSCAN key [MATCH match] [COUNT count] - -Iterate list keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### XLREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate list keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - - ### LDUMP key See [DUMP](#dump-key) for more information. @@ -1782,33 +1639,6 @@ ledis> STTL key (integer) -1 ``` -### SXSCAN key [MATCH match] [COUNT count] - -Iterate Set keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - - -### SXREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate Set keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - -### XSSCAN key [MATCH match] [COUNT count] - -Iterate Set keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - - -### XSREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate Set keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - - ### SDUMP key See [DUMP](#dump-key) for more information. @@ -2432,30 +2262,6 @@ ledis> ZRANGE out 0 -1 WITHSCORES 4) "10" ``` -### ZXSCAN key [MATCH match] [COUNT count] - -Iterate ZSet keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### ZXREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate ZSet keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - -### XZSCAN key [MATCH match] [COUNT count] - -Iterate ZSet keys incrementally. - -See [XSCAN](#xscan-key-match-match-count-count) for more information. - -### XZREVSCAN key [MATCH match] [COUNT count] - -Reverse iterate ZSet keys incrementally. - -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. - ### ZRANGEBYLEX key min max [LIMIT offset count] When all the elements in a sorted set are inserted with the same score, in order to force lexicographical ordering, this command returns all the elements in the sorted set at key with a value between min and max. @@ -2684,29 +2490,60 @@ ledis> BCOUNT flag 5 6 (refer to [PERSIST](#persist-key) api for other types) -### BXSCAN key [MATCH match] [COUNT count] +## Scan -Iterate Bitmap keys incrementally. +### XSCAN type cursor [MATCH match] [COUNT count] -See [XSCAN](#xscan-key-match-match-count-count) for more information. +Iterate data type keys incrementally. -### BXREVSCAN key [MATCH match] [COUNT count] +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. -Reverse iterate Bitmap keys incrementally. +**Return value** -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. +an array of two values, first value is the cursor for next iteration, second value is an array of elements. -### XBSCAN key [MATCH match] [COUNT count] +**Examples** -Iterate Bitmap keys incrementally. +``` +ledis>set a 1 +OK +ledis>set b 2 +OK +ledis>set c 3 +OK +127.0.0.1:6380>xscan "KV" "" +1) "" +2) ["a" "b" "c"] +ledis>xscan "KV" "" count 1 +1) "a" +2) ["a"] +ledis>xscan "KV" "a" count 1 +1) "b" +2) ["b"] +ledis>xscan "KV" "b" count 1 +1) "c" +2) ["c"] +ledis>xscan "KV" "c" count 1 +1) "" +2) [] +``` -See [XSCAN](#xscan-key-match-match-count-count) for more information. +### XHSCAN key cursor [MATCH match] [COUNT count] -### XBREVSCAN key [MATCH match] [COUNT count] +Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count), but return array of elements +contains two elements, a field and a value. -Reverse iterate Bitmap keys incrementally. +### XSSCAN key cursor [MATCH match] [COUNT count] -See [XREVSCAN](#xrevscan-key-match-match-count-count) for more information. +Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count) + +### XZSCAN key cursor [MATCH match] [COUNT count] + +Same like [XSCAN type cursor [MATCH match] [COUNT count]](#xscan-type-cursor-match-match-count-count), but return array of elements +contains two elements, a member and its associated score. ## Replication diff --git a/ledis/const.go b/ledis/const.go index 5d4b587..9bb0b70 100644 --- a/ledis/const.go +++ b/ledis/const.go @@ -6,6 +6,43 @@ import ( const Version = "0.4" +type DataType byte + +// for out use +const ( + KV DataType = iota + LIST + HASH + SET + ZSET +) + +func (d DataType) String() string { + switch d { + case KV: + return KVName + case LIST: + return ListName + case HASH: + return HashName + case SET: + return SetName + case ZSET: + return ZSetName + default: + return "unknown" + } +} + +const ( + KVName = "KV" + ListName = "LIST" + HashName = "HASH" + SetName = "SET" + ZSetName = "ZSET" +) + +// for backend store const ( NoneType byte = 0 KVType byte = 1 diff --git a/ledis/ledis_db.go b/ledis/ledis_db.go index ebde98e..4e2b490 100644 --- a/ledis/ledis_db.go +++ b/ledis/ledis_db.go @@ -128,7 +128,7 @@ func (db *DB) flushType(t *batch, dataType byte) (drop int64, err error) { } var keys [][]byte - keys, err = db.scan(metaDataType, nil, 1024, false, "") + keys, err = db.scanGeneric(metaDataType, nil, 1024, false, "", false) for len(keys) != 0 || err != nil { for _, key := range keys { deleteFunc(t, key) @@ -141,7 +141,7 @@ func (db *DB) flushType(t *batch, dataType byte) (drop int64, err error) { } else { drop += int64(len(keys)) } - keys, err = db.scan(metaDataType, nil, 1024, false, "") + keys, err = db.scanGeneric(metaDataType, nil, 1024, false, "", false) } return } diff --git a/ledis/scan.go b/ledis/scan.go index 9e8e235..c465168 100644 --- a/ledis/scan.go +++ b/ledis/scan.go @@ -9,19 +9,48 @@ import ( var errDataType = errors.New("error data type") var errMetaKey = errors.New("error meta key") -func (db *DB) scan(dataType byte, key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scanGeneric(dataType, key, count, inclusive, match, false) +//fif inclusive is true, scan range [cursor, inf) else (cursor, inf) +func (db *DB) Scan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) { + storeDataType, err := getDataStoreType(dataType) + if err != nil { + return nil, err + } + + return db.scanGeneric(storeDataType, cursor, count, inclusive, match, false) } -func (db *DB) revscan(dataType byte, key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scanGeneric(dataType, key, count, inclusive, match, true) +//if inclusive is true, revscan range (-inf, cursor] else (inf, cursor) +func (db *DB) RevScan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) { + storeDataType, err := getDataStoreType(dataType) + if err != nil { + return nil, err + } + + return db.scanGeneric(storeDataType, cursor, count, inclusive, match, true) } -func (db *DB) scanGeneric(dataType byte, key []byte, count int, - inclusive bool, match string, reverse bool) ([][]byte, error) { - var minKey, maxKey []byte +func getDataStoreType(dataType DataType) (byte, error) { + var storeDataType byte + switch dataType { + case KV: + storeDataType = KVType + case LIST: + storeDataType = LMetaType + case HASH: + storeDataType = HSizeType + case SET: + storeDataType = SSizeType + case ZSET: + storeDataType = ZSizeType + default: + return 0, errDataType + } + return storeDataType, nil +} + +func buildMatchRegexp(match string) (*regexp.Regexp, error) { var err error - var r *regexp.Regexp + var r *regexp.Regexp = nil if len(match) > 0 { if r, err = regexp.Compile(match); err != nil { @@ -29,13 +58,24 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int, } } + 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 + } + tp := store.RangeOpen if !reverse { - if minKey, err = db.encodeScanMinKey(dataType, key); err != nil { + if minKey, err = db.encodeScanMinKey(storeDataType, key); err != nil { return nil, err } - if maxKey, err = db.encodeScanMaxKey(dataType, nil); err != nil { + if maxKey, err = db.encodeScanMaxKey(storeDataType, nil); err != nil { return nil, err } @@ -43,10 +83,10 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int, tp = store.RangeROpen } } else { - if minKey, err = db.encodeScanMinKey(dataType, nil); err != nil { + if minKey, err = db.encodeScanMinKey(storeDataType, nil); err != nil { return nil, err } - if maxKey, err = db.encodeScanMaxKey(dataType, key); err != nil { + if maxKey, err = db.encodeScanMaxKey(storeDataType, key); err != nil { return nil, err } @@ -69,7 +109,7 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int, v := make([][]byte, 0, count) for i := 0; it.Valid() && i < count; it.Next() { - if k, err := db.decodeScanKey(dataType, it.Key()); err != nil { + if k, err := db.decodeScanKey(storeDataType, it.Key()); err != nil { continue } else if r != nil && !r.Match(k) { continue @@ -82,36 +122,36 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int, return v, nil } -func (db *DB) encodeScanMinKey(dataType byte, key []byte) ([]byte, error) { +func (db *DB) encodeScanMinKey(storeDataType byte, key []byte) ([]byte, error) { if len(key) == 0 { - return db.encodeScanKey(dataType, nil) + return db.encodeScanKey(storeDataType, nil) } else { if err := checkKeySize(key); err != nil { return nil, err } - return db.encodeScanKey(dataType, key) + return db.encodeScanKey(storeDataType, key) } } -func (db *DB) encodeScanMaxKey(dataType byte, key []byte) ([]byte, error) { +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(dataType, key) + return db.encodeScanKey(storeDataType, key) } - k, err := db.encodeScanKey(dataType, nil) + k, err := db.encodeScanKey(storeDataType, nil) if err != nil { return nil, err } - k[len(k)-1] = dataType + 1 + k[len(k)-1] = storeDataType + 1 return k, nil } -func (db *DB) encodeScanKey(dataType byte, key []byte) ([]byte, error) { - switch dataType { +func (db *DB) encodeScanKey(storeDataType byte, key []byte) ([]byte, error) { + switch storeDataType { case KVType: return db.encodeKVKey(key), nil case LMetaType: @@ -120,17 +160,137 @@ func (db *DB) encodeScanKey(dataType byte, key []byte) ([]byte, error) { return db.hEncodeSizeKey(key), nil case ZSizeType: return db.zEncodeSizeKey(key), nil - case BitMetaType: - return db.bEncodeMetaKey(key), nil case SSizeType: return db.sEncodeSizeKey(key), nil + case BitMetaType: + return db.bEncodeMetaKey(key), nil default: return nil, errDataType } } -func (db *DB) decodeScanKey(dataType byte, ek []byte) ([]byte, error) { - if len(ek) < 2 || ek[0] != db.index || ek[1] != dataType { +func (db *DB) decodeScanKey(storeDataType byte, ek []byte) ([]byte, error) { + if len(ek) < 2 || ek[0] != db.index || ek[1] != storeDataType { return nil, errMetaKey } return ek[2:], nil } + +// for specail data scan + +func (db *DB) buildDataScanIterator(start []byte, stop []byte, inclusive bool) *store.RangeLimitIterator { + tp := store.RangeROpen + + if !inclusive { + tp = store.RangeOpen + } + it := db.bucket.RangeIterator(start, stop, tp) + return it + +} + +func (db *DB) HScan(key []byte, cursor []byte, count int, inclusive bool, match string) ([]FVPair, error) { + if err := checkKeySize(key); err != nil { + return nil, err + } + + start := db.hEncodeHashKey(key, cursor) + stop := db.hEncodeStopKey(key) + + v := make([]FVPair, 0, 16) + + r, err := buildMatchRegexp(match) + if err != nil { + return nil, err + } + + it := db.buildDataScanIterator(start, stop, inclusive) + defer it.Close() + + for i := 0; it.Valid() && i < count; it.Next() { + _, f, err := db.hDecodeHashKey(it.Key()) + if err != nil { + return nil, err + } else if r != nil && !r.Match(f) { + continue + } + + v = append(v, FVPair{Field: f, Value: it.Value()}) + + i++ + } + + 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 + } + + start := db.sEncodeSetKey(key, cursor) + stop := db.sEncodeStopKey(key) + + v := make([][]byte, 0, 16) + + r, err := buildMatchRegexp(match) + if err != nil { + return nil, err + } + + it := db.buildDataScanIterator(start, stop, inclusive) + defer it.Close() + + for i := 0; it.Valid() && i < count; it.Next() { + _, m, err := db.sDecodeSetKey(it.Key()) + if err != nil { + return nil, err + } else if r != nil && !r.Match(m) { + continue + } + + v = append(v, m) + + i++ + } + + 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 + } + + start := db.zEncodeSetKey(key, cursor) + stop := db.zEncodeStopSetKey(key) + + v := make([]ScorePair, 0, 16) + + r, err := buildMatchRegexp(match) + if err != nil { + return nil, err + } + + it := db.buildDataScanIterator(start, stop, inclusive) + defer it.Close() + + for i := 0; it.Valid() && i < count; it.Next() { + _, m, err := db.zDecodeSetKey(it.Key()) + if err != nil { + return nil, err + } else if r != nil && !r.Match(m) { + continue + } + + score, err := Int64(it.Value(), nil) + if err != nil { + return nil, err + } + + v = append(v, ScorePair{Score: score, Member: m}) + + i++ + } + + return v, nil +} diff --git a/ledis/scan_test.go b/ledis/scan_test.go index b2a0970..9505964 100644 --- a/ledis/scan_test.go +++ b/ledis/scan_test.go @@ -21,13 +21,13 @@ func TestDBScan(t *testing.T) { db.FlushAll() - if v, err := db.Scan(nil, 10, true, ""); err != nil { + if v, err := db.Scan(KV, nil, 10, true, ""); err != nil { t.Fatal(err) } else if len(v) != 0 { t.Fatal(len(v)) } - if v, err := db.RevScan(nil, 10, true, ""); err != nil { + if v, err := db.RevScan(KV, nil, 10, true, ""); err != nil { t.Fatal(err) } else if len(v) != 0 { t.Fatal(len(v)) @@ -37,73 +37,73 @@ func TestDBScan(t *testing.T) { db.Set([]byte("b"), []byte{}) db.Set([]byte("c"), []byte{}) - if v, err := db.Scan(nil, 1, true, ""); err != nil { + if v, err := db.Scan(KV, nil, 1, true, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "a") } - if v, err := db.Scan([]byte("a"), 2, false, ""); err != nil { + if v, err := db.Scan(KV, []byte("a"), 2, false, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "b", "c") } - if v, err := db.Scan(nil, 3, true, ""); err != nil { + if v, err := db.Scan(KV, nil, 3, true, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "a", "b", "c") } - if v, err := db.Scan(nil, 3, true, "b"); err != nil { + if v, err := db.Scan(KV, nil, 3, true, "b"); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "b") } - if v, err := db.Scan(nil, 3, true, "."); err != nil { + if v, err := db.Scan(KV, nil, 3, true, "."); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "a", "b", "c") } - if v, err := db.Scan(nil, 3, true, "a+"); err != nil { + if v, err := db.Scan(KV, nil, 3, true, "a+"); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "a") } - if v, err := db.RevScan(nil, 1, true, ""); err != nil { + if v, err := db.RevScan(KV, nil, 1, true, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "c") } - if v, err := db.RevScan([]byte("c"), 2, false, ""); err != nil { + if v, err := db.RevScan(KV, []byte("c"), 2, false, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "b", "a") } - if v, err := db.RevScan(nil, 3, true, ""); err != nil { + if v, err := db.RevScan(KV, nil, 3, true, ""); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "c", "b", "a") } - if v, err := db.RevScan(nil, 3, true, "b"); err != nil { + if v, err := db.RevScan(KV, nil, 3, true, "b"); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "b") } - if v, err := db.RevScan(nil, 3, true, "."); err != nil { + if v, err := db.RevScan(KV, nil, 3, true, "."); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "c", "b", "a") } - if v, err := db.RevScan(nil, 3, true, "c+"); err != nil { + if v, err := db.RevScan(KV, nil, 3, true, "c+"); err != nil { t.Fatal(err) } else { checkTestScan(t, v, "c") @@ -111,7 +111,7 @@ func TestDBScan(t *testing.T) { } -func TestDBHScan(t *testing.T) { +func TestDBHKeyScan(t *testing.T) { db := getTestDB() db.hFlush() @@ -125,7 +125,7 @@ func TestDBHScan(t *testing.T) { k3 := []byte("k3") db.HSet(k3, []byte("3"), []byte{}) - if v, err := db.HScan(nil, 1, true, ""); err != nil { + if v, err := db.Scan(HASH, nil, 1, true, ""); err != nil { t.Fatal(err) } else if len(v) != 1 { t.Fatal("invalid length ", len(v)) @@ -133,7 +133,7 @@ func TestDBHScan(t *testing.T) { t.Fatal("invalid value ", string(v[0])) } - if v, err := db.HScan(k1, 2, true, ""); err != nil { + if v, err := db.Scan(HASH, k1, 2, true, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -143,7 +143,7 @@ func TestDBHScan(t *testing.T) { t.Fatal("invalid value ", string(v[1])) } - if v, err := db.HScan(k1, 2, false, ""); err != nil { + if v, err := db.Scan(HASH, k1, 2, false, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -155,7 +155,7 @@ func TestDBHScan(t *testing.T) { } -func TestDBZScan(t *testing.T) { +func TestDBZKeyScan(t *testing.T) { db := getTestDB() db.zFlush() @@ -169,7 +169,7 @@ func TestDBZScan(t *testing.T) { k3 := []byte("k3") db.ZAdd(k3, ScorePair{3, []byte("m")}) - if v, err := db.ZScan(nil, 1, true, ""); err != nil { + if v, err := db.Scan(ZSET, nil, 1, true, ""); err != nil { t.Fatal(err) } else if len(v) != 1 { t.Fatal("invalid length ", len(v)) @@ -177,7 +177,7 @@ func TestDBZScan(t *testing.T) { t.Fatal("invalid value ", string(v[0])) } - if v, err := db.ZScan(k1, 2, true, ""); err != nil { + if v, err := db.Scan(ZSET, k1, 2, true, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -187,7 +187,7 @@ func TestDBZScan(t *testing.T) { t.Fatal("invalid value ", string(v[1])) } - if v, err := db.ZScan(k1, 2, false, ""); err != nil { + if v, err := db.Scan(ZSET, k1, 2, false, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -199,7 +199,7 @@ func TestDBZScan(t *testing.T) { } -func TestDBLScan(t *testing.T) { +func TestDBLKeyScan(t *testing.T) { db := getTestDB() db.lFlush() @@ -219,7 +219,7 @@ func TestDBLScan(t *testing.T) { t.Fatal(err.Error()) } - if v, err := db.LScan(nil, 1, true, ""); err != nil { + if v, err := db.Scan(LIST, nil, 1, true, ""); err != nil { t.Fatal(err) } else if len(v) != 1 { t.Fatal("invalid length ", len(v)) @@ -227,7 +227,7 @@ func TestDBLScan(t *testing.T) { t.Fatal("invalid value ", string(v[0])) } - if v, err := db.LScan(k1, 2, true, ""); err != nil { + if v, err := db.Scan(LIST, k1, 2, true, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -237,7 +237,7 @@ func TestDBLScan(t *testing.T) { t.Fatal("invalid value ", string(v[1])) } - if v, err := db.LScan(k1, 2, false, ""); err != nil { + if v, err := db.Scan(LIST, k1, 2, false, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -249,60 +249,10 @@ func TestDBLScan(t *testing.T) { } -func TestDBBScan(t *testing.T) { - // db := getTestDB() - - // db.bFlush() - - // k1 := []byte("k1") - // if _, err := db.BSetBit(k1, 1, 1); err != nil { - // t.Fatal(err.Error()) - // } - - // k2 := []byte("k2") - // if _, err := db.BSetBit(k2, 1, 1); err != nil { - // t.Fatal(err.Error()) - // } - // k3 := []byte("k3") - - // if _, err := db.BSetBit(k3, 1, 0); err != nil { - // t.Fatal(err.Error()) - // } - - // if v, err := db.BScan(nil, 1, true, ""); err != nil { - // t.Fatal(err) - // } else if len(v) != 1 { - // t.Fatal("invalid length ", len(v)) - // } else if string(v[0]) != "k1" { - // t.Fatal("invalid value ", string(v[0])) - // } - - // if v, err := db.BScan(k1, 2, true, ""); err != nil { - // t.Fatal(err) - // } else if len(v) != 2 { - // t.Fatal("invalid length ", len(v)) - // } else if string(v[0]) != "k1" { - // t.Fatal("invalid value ", string(v[0])) - // } else if string(v[1]) != "k2" { - // t.Fatal("invalid value ", string(v[1])) - // } - - // if v, err := db.BScan(k1, 2, false, ""); err != nil { - // t.Fatal(err) - // } else if len(v) != 2 { - // t.Fatal("invalid length ", len(v)) - // } else if string(v[0]) != "k2" { - // t.Fatal("invalid value ", string(v[0])) - // } else if string(v[1]) != "k3" { - // t.Fatal("invalid value ", string(v[1])) - // } - -} - -func TestDBSScan(t *testing.T) { +func TestDBSKeyScan(t *testing.T) { db := getTestDB() - db.bFlush() + db.sFlush() k1 := []byte("k1") if _, err := db.SAdd(k1, []byte("1")); err != nil { @@ -319,7 +269,7 @@ func TestDBSScan(t *testing.T) { t.Fatal(err.Error()) } - if v, err := db.SScan(nil, 1, true, ""); err != nil { + if v, err := db.Scan(SET, nil, 1, true, ""); err != nil { t.Fatal(err) } else if len(v) != 1 { t.Fatal("invalid length ", len(v)) @@ -327,7 +277,7 @@ func TestDBSScan(t *testing.T) { t.Fatal("invalid value ", string(v[0])) } - if v, err := db.SScan(k1, 2, true, ""); err != nil { + if v, err := db.Scan(SET, k1, 2, true, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -337,7 +287,7 @@ func TestDBSScan(t *testing.T) { t.Fatal("invalid value ", string(v[1])) } - if v, err := db.SScan(k1, 2, false, ""); err != nil { + if v, err := db.Scan(SET, k1, 2, false, ""); err != nil { t.Fatal(err) } else if len(v) != 2 { t.Fatal("invalid length ", len(v)) @@ -346,5 +296,77 @@ func TestDBSScan(t *testing.T) { } else if string(v[1]) != "k3" { t.Fatal("invalid value ", string(v[1])) } - +} + +func TestDBHScan(t *testing.T) { + db := getTestDB() + + key := []byte("scan_h_key") + value := []byte("hello world") + db.HSet(key, []byte("1"), value) + db.HSet(key, []byte("222"), value) + db.HSet(key, []byte("19"), value) + db.HSet(key, []byte("1234"), value) + + v, err := db.HScan(key, nil, 100, true, "") + if err != nil { + t.Fatal(err) + } else if len(v) != 4 { + t.Fatal("invalid count", len(v)) + } + + v, err = db.HScan(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) != "222" { + t.Fatal(string(v[0].Field)) + } +} + +func TestDBSScan(t *testing.T) { + db := getTestDB() + key := []byte("scan_s_key") + + db.SAdd(key, []byte("1"), []byte("222"), []byte("19"), []byte("1234")) + + v, err := db.SScan(key, nil, 100, true, "") + if err != nil { + t.Fatal(err) + } else if len(v) != 4 { + t.Fatal("invalid count", len(v)) + } + + v, err = db.SScan(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]) != "222" { + t.Fatal(string(v[0])) + } +} + +func TestDBZScan(t *testing.T) { + db := getTestDB() + key := []byte("scan_z_key") + + db.ZAdd(key, ScorePair{1, []byte("1")}, ScorePair{2, []byte("222")}, ScorePair{3, []byte("19")}, ScorePair{4, []byte("1234")}) + + v, err := db.ZScan(key, nil, 100, true, "") + if err != nil { + t.Fatal(err) + } else if len(v) != 4 { + t.Fatal("invalid count", len(v)) + } + + v, err = db.ZScan(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) != "222" { + t.Fatal(string(v[0].Member)) + } } diff --git a/ledis/t_bit.go b/ledis/t_bit.go index cff51d6..d89f15b 100644 --- a/ledis/t_bit.go +++ b/ledis/t_bit.go @@ -922,16 +922,6 @@ func (db *DB) BPersist(key []byte) (int64, error) { return n, err } -func (db *DB) BScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - log.Error("bitmap type will be deprecated later, please use bit operations in kv type") - return db.scan(BitMetaType, key, count, inclusive, match) -} - -func (db *DB) BRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - log.Error("bitmap type will be deprecated later, please use bit operations in kv type") - return db.revscan(BitMetaType, key, count, inclusive, match) -} - func (db *DB) bFlush() (drop int64, err error) { t := db.binBatch t.Lock() diff --git a/ledis/t_hash.go b/ledis/t_hash.go index 6235acc..c7b92dd 100644 --- a/ledis/t_hash.go +++ b/ledis/t_hash.go @@ -354,6 +354,8 @@ func (db *DB) HGetAll(key []byte) ([]FVPair, error) { v := make([]FVPair, 0, 16) it := db.bucket.RangeLimitIterator(start, stop, store.RangeROpen, 0, -1) + defer it.Close() + for ; it.Valid(); it.Next() { _, f, err := db.hDecodeHashKey(it.Key()) if err != nil { @@ -363,8 +365,6 @@ func (db *DB) HGetAll(key []byte) ([]FVPair, error) { v = append(v, FVPair{Field: f, Value: it.Value()}) } - it.Close() - return v, nil } @@ -379,6 +379,8 @@ func (db *DB) HKeys(key []byte) ([][]byte, error) { v := make([][]byte, 0, 16) it := db.bucket.RangeLimitIterator(start, stop, store.RangeROpen, 0, -1) + defer it.Close() + for ; it.Valid(); it.Next() { _, f, err := db.hDecodeHashKey(it.Key()) if err != nil { @@ -387,8 +389,6 @@ func (db *DB) HKeys(key []byte) ([][]byte, error) { v = append(v, f) } - it.Close() - return v, nil } @@ -403,6 +403,8 @@ func (db *DB) HValues(key []byte) ([][]byte, error) { v := make([][]byte, 0, 16) it := db.bucket.RangeLimitIterator(start, stop, store.RangeROpen, 0, -1) + defer it.Close() + for ; it.Valid(); it.Next() { _, _, err := db.hDecodeHashKey(it.Key()) if err != nil { @@ -412,8 +414,6 @@ func (db *DB) HValues(key []byte) ([][]byte, error) { v = append(v, it.Value()) } - it.Close() - return v, nil } @@ -460,14 +460,6 @@ func (db *DB) hFlush() (drop int64, err error) { return db.flushType(t, HashType) } -func (db *DB) HScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scan(HSizeType, key, count, inclusive, match) -} - -func (db *DB) HRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.revscan(HSizeType, key, count, inclusive, match) -} - func (db *DB) HExpire(key []byte, duration int64) (int64, error) { if duration <= 0 { return 0, errExpireValue diff --git a/ledis/t_hash_test.go b/ledis/t_hash_test.go index 7fac691..6afa2da 100644 --- a/ledis/t_hash_test.go +++ b/ledis/t_hash_test.go @@ -114,7 +114,7 @@ func TestHFlush(t *testing.T) { } } - if v, err := db.HScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(HASH, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 2000 { t.Fatal("invalid value ", len(v)) @@ -135,7 +135,7 @@ func TestHFlush(t *testing.T) { t.Fatal("invalid value ", n) } - if v, err := db.HScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(HASH, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 0 { t.Fatal("invalid value length ", len(v)) diff --git a/ledis/t_kv.go b/ledis/t_kv.go index 398d2a8..eb2f1fe 100644 --- a/ledis/t_kv.go +++ b/ledis/t_kv.go @@ -347,16 +347,6 @@ func (db *DB) flush() (drop int64, err error) { return db.flushType(t, KVType) } -//if inclusive is true, scan range [key, inf) else (key, inf) -func (db *DB) Scan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scan(KVType, key, count, inclusive, match) -} - -//if inclusive is true, revscan range (-inf, key] else (inf, key) -func (db *DB) RevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.revscan(KVType, key, count, inclusive, match) -} - func (db *DB) Expire(key []byte, duration int64) (int64, error) { if duration <= 0 { return 0, errExpireValue diff --git a/ledis/t_kv_test.go b/ledis/t_kv_test.go index 63ea052..ffbac81 100644 --- a/ledis/t_kv_test.go +++ b/ledis/t_kv_test.go @@ -282,7 +282,7 @@ func TestKVFlush(t *testing.T) { } } - if v, err := db.Scan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(KV, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 2000 { t.Fatal("invalid value ", len(v)) @@ -303,7 +303,7 @@ func TestKVFlush(t *testing.T) { t.Fatal("invalid value ", n) } - if v, err := db.Scan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(KV, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 0 { t.Fatal("invalid value length ", len(v)) diff --git a/ledis/t_list.go b/ledis/t_list.go index 93c6ba2..c2cc5a9 100644 --- a/ledis/t_list.go +++ b/ledis/t_list.go @@ -480,14 +480,6 @@ func (db *DB) LPersist(key []byte) (int64, error) { return n, err } -func (db *DB) LScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scan(LMetaType, key, count, inclusive, match) -} - -func (db *DB) LRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.revscan(LMetaType, key, count, inclusive, match) -} - func (db *DB) lEncodeMinKey() []byte { return db.lEncodeMetaKey(nil) } diff --git a/ledis/t_list_test.go b/ledis/t_list_test.go index b80af1d..58c1c58 100644 --- a/ledis/t_list_test.go +++ b/ledis/t_list_test.go @@ -145,7 +145,7 @@ func TestLFlush(t *testing.T) { } } - if v, err := db.LScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(LIST, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 2000 { t.Fatal("invalid value ", len(v)) @@ -157,7 +157,7 @@ func TestLFlush(t *testing.T) { t.Fatal("invalid value ", n) } - if v, err := db.LScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(LIST, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 0 { t.Fatal("invalid value length ", len(v)) diff --git a/ledis/t_set.go b/ledis/t_set.go index 126b407..200d66b 100644 --- a/ledis/t_set.go +++ b/ledis/t_set.go @@ -607,11 +607,3 @@ func (db *DB) SPersist(key []byte) (int64, error) { err = t.Commit() return n, err } - -func (db *DB) SScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scan(SSizeType, key, count, inclusive, match) -} - -func (db *DB) SRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.revscan(SSizeType, key, count, inclusive, match) -} diff --git a/ledis/t_set_test.go b/ledis/t_set_test.go index eb24bdb..b6b1460 100644 --- a/ledis/t_set_test.go +++ b/ledis/t_set_test.go @@ -352,7 +352,7 @@ func TestSFlush(t *testing.T) { } } - if v, err := db.SScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(SET, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 2000 { t.Fatal("invalid value ", len(v)) @@ -364,7 +364,7 @@ func TestSFlush(t *testing.T) { t.Fatal("invalid value ", n) } - if v, err := db.SScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(SET, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 0 { t.Fatal("invalid value length ", len(v)) diff --git a/ledis/t_zset.go b/ledis/t_zset.go index 36f886b..0bd22a3 100644 --- a/ledis/t_zset.go +++ b/ledis/t_zset.go @@ -936,14 +936,6 @@ func (db *DB) ZInterStore(destKey []byte, srcKeys [][]byte, weights []int64, agg return n, nil } -func (db *DB) ZScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.scan(ZSizeType, key, count, inclusive, match) -} - -func (db *DB) ZRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) { - return db.revscan(ZSizeType, key, count, inclusive, match) -} - func (db *DB) ZRangeByLex(key []byte, min []byte, max []byte, rangeType uint8, offset int, count int) ([][]byte, error) { if min == nil { min = db.zEncodeStartSetKey(key) diff --git a/ledis/t_zset_test.go b/ledis/t_zset_test.go index cdb35bc..6323091 100644 --- a/ledis/t_zset_test.go +++ b/ledis/t_zset_test.go @@ -391,7 +391,7 @@ func TestZScan(t *testing.T) { } } - if v, err := db.ZScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(ZSET, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 2000 { t.Fatal("invalid value ", len(v)) @@ -403,7 +403,7 @@ func TestZScan(t *testing.T) { t.Fatal("invalid value ", n) } - if v, err := db.ZScan(nil, 3000, true, ""); err != nil { + if v, err := db.Scan(ZSET, nil, 3000, true, ""); err != nil { t.Fatal(err.Error()) } else if len(v) != 0 { t.Fatal("invalid value length ", len(v)) diff --git a/server/cmd_bit.go b/server/cmd_bit.go index ac577ea..45d6ede 100644 --- a/server/cmd_bit.go +++ b/server/cmd_bit.go @@ -274,14 +274,6 @@ func bpersistCommand(c *client) error { return nil } -func bxscanCommand(c *client) error { - return xscanGeneric(c, c.db.BScan) -} - -func bxrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.BRevScan) -} - func init() { register("bget", bgetCommand) register("bdelete", bdeleteCommand) @@ -294,8 +286,4 @@ func init() { register("bexpireat", bexpireAtCommand) register("bttl", bttlCommand) register("bpersist", bpersistCommand) - register("bxscan", bxscanCommand) - register("bxrevscan", bxrevscanCommand) - register("xbscan", bxscanCommand) - register("xbrevscan", bxrevscanCommand) } diff --git a/server/cmd_hash.go b/server/cmd_hash.go index 8c277ee..b9acc85 100644 --- a/server/cmd_hash.go +++ b/server/cmd_hash.go @@ -292,14 +292,6 @@ func hpersistCommand(c *client) error { return nil } -func hxscanCommand(c *client) error { - return xscanGeneric(c, c.db.HScan) -} - -func hxrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.HRevScan) -} - func xhexistsCommand(c *client) error { args := c.args if len(args) != 1 { @@ -334,9 +326,5 @@ func init() { register("hexpireat", hexpireAtCommand) register("httl", httlCommand) register("hpersist", hpersistCommand) - register("hxscan", hxscanCommand) - register("hxrevscan", hxrevscanCommand) - register("xhscan", hxscanCommand) - register("xhrevscan", hxrevscanCommand) register("xhexists", xhexistsCommand) } diff --git a/server/cmd_kv.go b/server/cmd_kv.go index 45a4b7a..25d7bb9 100644 --- a/server/cmd_kv.go +++ b/server/cmd_kv.go @@ -1,10 +1,8 @@ package server import ( - "github.com/siddontang/go/hack" "github.com/siddontang/ledisdb/ledis" "strconv" - "strings" ) // func getCommand(c *client) error { @@ -315,82 +313,6 @@ func persistCommand(c *client) error { return nil } -func parseScanArgs(c *client) (key []byte, match string, count int, err error) { - args := c.args - count = 10 - - switch len(args) { - case 0: - key = nil - return - case 1, 3, 5: - key = args[0] - break - default: - err = ErrCmdParams - return - } - - if len(args) == 3 { - switch strings.ToLower(hack.String(args[1])) { - case "match": - match = hack.String(args[2]) - case "count": - count, err = strconv.Atoi(hack.String(args[2])) - default: - err = ErrCmdParams - return - } - } else if len(args) == 5 { - if strings.ToLower(hack.String(args[1])) != "match" { - err = ErrCmdParams - return - } else if strings.ToLower(hack.String(args[3])) != "count" { - err = ErrCmdParams - return - } - - match = hack.String(args[2]) - count, err = strconv.Atoi(hack.String(args[4])) - } - - if count <= 0 { - err = ErrCmdParams - } - - return -} - -func xscanGeneric(c *client, - f func(key []byte, count int, inclusive bool, match string) ([][]byte, error)) error { - key, match, count, err := parseScanArgs(c) - if err != nil { - return err - } - - if ay, err := f(key, count, false, match); err != nil { - return err - } else { - data := make([]interface{}, 2) - if len(ay) < count { - data[0] = []byte("") - } else { - data[0] = ay[len(ay)-1] - } - data[1] = ay - c.resp.writeArray(data) - } - return nil -} - -func xscanCommand(c *client) error { - return xscanGeneric(c, c.db.Scan) -} - -func xrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.RevScan) -} - func appendCommand(c *client) error { args := c.args if len(args) != 2 { @@ -619,6 +541,4 @@ func init() { register("expireat", expireAtCommand) register("ttl", ttlCommand) register("persist", persistCommand) - register("xscan", xscanCommand) - register("xrevscan", xrevscanCommand) } diff --git a/server/cmd_list.go b/server/cmd_list.go index 7000a74..d3ac6e2 100644 --- a/server/cmd_list.go +++ b/server/cmd_list.go @@ -231,14 +231,6 @@ func lpersistCommand(c *client) error { return nil } -func lxscanCommand(c *client) error { - return xscanGeneric(c, c.db.LScan) -} - -func lxrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.LRevScan) -} - func blpopCommand(c *client) error { keys, timeout, err := lParseBPopArgs(c) if err != nil { @@ -317,9 +309,5 @@ func init() { register("lexpireat", lexpireAtCommand) register("lttl", lttlCommand) register("lpersist", lpersistCommand) - register("lxscan", lxscanCommand) - register("lxrevscan", lxrevscanCommand) - register("xlscan", lxscanCommand) - register("xlrevscan", lxrevscanCommand) register("xlexists", xlexistsCommand) } diff --git a/server/cmd_migrate.go b/server/cmd_migrate.go index 3153821..a162328 100644 --- a/server/cmd_migrate.go +++ b/server/cmd_migrate.go @@ -165,15 +165,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": - return db.Scan(nil, count, false, "") + return db.Scan(KV, nil, count, false, "") case "HASH": - return db.HScan(nil, count, false, "") + return db.Scan(HASH, nil, count, false, "") case "LIST": - return db.LScan(nil, count, false, "") + return db.Scan(LIST, nil, count, false, "") case "SET": - return db.SScan(nil, count, false, "") + return db.Scan(SET, nil, count, false, "") case "ZSET": - return db.ZScan(nil, count, false, "") + return db.Scan(ZSET, nil, count, false, "") default: return nil, fmt.Errorf("invalid key type %s", tp) } diff --git a/server/cmd_replication_test.go b/server/cmd_replication_test.go index 530d7db..66b99c7 100644 --- a/server/cmd_replication_test.go +++ b/server/cmd_replication_test.go @@ -14,8 +14,8 @@ func checkDataEqual(master *App, slave *App) error { mdb, _ := master.ldb.Select(0) sdb, _ := slave.ldb.Select(0) - mkeys, _ := mdb.Scan(nil, 100, true, "") - skeys, _ := sdb.Scan(nil, 100, true, "") + mkeys, _ := mdb.Scan(KV, nil, 100, true, "") + skeys, _ := sdb.Scan(KV, nil, 100, true, "") if len(mkeys) != len(skeys) { return fmt.Errorf("keys number not equal %d != %d", len(mkeys), len(skeys)) diff --git a/server/cmd_scan.go b/server/cmd_scan.go new file mode 100644 index 0000000..1e62d8f --- /dev/null +++ b/server/cmd_scan.go @@ -0,0 +1,215 @@ +package server + +import ( + "fmt" + "github.com/siddontang/go/hack" + "github.com/siddontang/go/num" + "github.com/siddontang/ledisdb/ledis" + "strconv" + "strings" +) + +func parseScanArgs(args [][]byte) (cursor []byte, match string, count int, err error) { + cursor = args[0] + + args = args[1:] + + count = 10 + + for i := 0; i < len(args); { + switch strings.ToUpper(hack.String(args[i])) { + case "MATCH": + if i+1 >= len(args) { + err = ErrCmdParams + return + } + + match = hack.String(args[i+1]) + i = i + 2 + case "COUNT": + if i+1 >= len(args) { + err = ErrCmdParams + return + } + + count, err = strconv.Atoi(hack.String(args[i+1])) + if err != nil { + return + } + + i = i + 2 + default: + err = fmt.Errorf("invalid argument %s", args[i]) + return + } + } + + return +} + +// XSCAN type cursor [MATCH match] [COUNT count] +func xscanCommand(c *client) error { + args := c.args + + if len(args) < 2 { + return ErrCmdParams + } + + var dataType ledis.DataType + switch strings.ToUpper(hack.String(args[0])) { + case "KV": + dataType = ledis.KV + case "HASH": + dataType = ledis.HASH + case "LIST": + dataType = ledis.LIST + case "SET": + dataType = ledis.SET + case "ZSET": + dataType = ledis.ZSET + default: + return fmt.Errorf("invalid key type %s", args[0]) + } + + cursor, match, count, err := parseScanArgs(args[1:]) + + if err != nil { + return err + } + + ay, err := c.db.Scan(dataType, cursor, count, false, match) + if err != nil { + return err + } + + data := make([]interface{}, 2) + if len(ay) < count { + data[0] = []byte("") + } else { + data[0] = ay[len(ay)-1] + } + data[1] = ay + c.resp.writeArray(data) + return nil +} + +// XHSCAN key cursor [MATCH match] [COUNT count] +func xhscanCommand(c *client) error { + args := c.args + + if len(args) < 2 { + return ErrCmdParams + } + + key := args[0] + + cursor, match, count, err := parseScanArgs(args[1:]) + + if err != nil { + return err + } + + ay, err := c.db.HScan(key, cursor, count, false, match) + if err != nil { + return err + } + + data := make([]interface{}, 2) + if len(ay) < count { + data[0] = []byte("") + } else { + data[0] = ay[len(ay)-1].Field + } + + vv := make([][]byte, 0, len(ay)*2) + + for _, v := range ay { + vv = append(vv, v.Field, v.Value) + } + + data[1] = vv + + c.resp.writeArray(data) + return nil +} + +// XSSCAN key cursor [MATCH match] [COUNT count] +func xsscanCommand(c *client) error { + args := c.args + + if len(args) < 2 { + return ErrCmdParams + } + + key := args[0] + + cursor, match, count, err := parseScanArgs(args[1:]) + + if err != nil { + return err + } + + ay, err := c.db.SScan(key, cursor, count, false, match) + if err != nil { + return err + } + + data := make([]interface{}, 2) + if len(ay) < count { + data[0] = []byte("") + } else { + data[0] = ay[len(ay)-1] + } + + data[1] = ay + + c.resp.writeArray(data) + return nil +} + +// XZSCAN key cursor [MATCH match] [COUNT count] +func xzscanCommand(c *client) error { + args := c.args + + if len(args) < 2 { + return ErrCmdParams + } + + key := args[0] + + cursor, match, count, err := parseScanArgs(args[1:]) + + if err != nil { + return err + } + + ay, err := c.db.ZScan(key, cursor, count, false, match) + if err != nil { + return err + } + + data := make([]interface{}, 2) + if len(ay) < count { + data[0] = []byte("") + } else { + data[0] = ay[len(ay)-1].Member + } + + vv := make([][]byte, 0, len(ay)*2) + + for _, v := range ay { + vv = append(vv, v.Member, num.FormatInt64ToSlice(v.Score)) + } + + data[1] = vv + + c.resp.writeArray(data) + return nil +} + +func init() { + register("xscan", xscanCommand) + register("xhscan", xhscanCommand) + register("xsscan", xsscanCommand) + register("xzscan", xzscanCommand) +} diff --git a/server/scan_test.go b/server/cmd_scan_test.go similarity index 58% rename from server/scan_test.go rename to server/cmd_scan_test.go index 1778416..7ebb5ba 100644 --- a/server/scan_test.go +++ b/server/cmd_scan_test.go @@ -29,14 +29,14 @@ func TestScan(t *testing.T) { defer c.Close() testKVScan(t, c) - testHashScan(t, c) - testListScan(t, c) - testZSetScan(t, c) - testSetScan(t, c) + testHashKeyScan(t, c) + testListKeyScan(t, c) + testZSetKeyScan(t, c) + testSetKeyScan(t, c) } -func checkScanValues(t *testing.T, ay interface{}, values ...int) { +func checkScanValues(t *testing.T, ay interface{}, values ...interface{}) { a, err := ledis.Strings(ay, nil) if err != nil { t.Fatal(err) @@ -47,14 +47,14 @@ func checkScanValues(t *testing.T, ay interface{}, values ...int) { } for i, v := range a { - if string(v) != fmt.Sprintf("%d", values[i]) { - t.Fatal(fmt.Sprintf("%d %s != %d", string(v), values[i])) + if string(v) != fmt.Sprintf("%v", values[i]) { + t.Fatal(fmt.Sprintf("%d %s != %v", string(v), values[i])) } } } -func checkScan(t *testing.T, c *ledis.Client, cmd string) { - if ay, err := ledis.Values(c.Do(cmd, "", "count", 5)); err != nil { +func checkScan(t *testing.T, c *ledis.Client, tp string) { + if ay, err := ledis.Values(c.Do("XSCAN", tp, "", "count", 5)); err != nil { t.Fatal(err) } else if len(ay) != 2 { t.Fatal(len(ay)) @@ -64,7 +64,7 @@ func checkScan(t *testing.T, c *ledis.Client, cmd string) { checkScanValues(t, ay[1], 0, 1, 2, 3, 4) } - if ay, err := ledis.Values(c.Do(cmd, "4", "count", 6)); err != nil { + if ay, err := ledis.Values(c.Do("XSCAN", tp, "4", "count", 6)); err != nil { t.Fatal(err) } else if len(ay) != 2 { t.Fatal(len(ay)) @@ -76,29 +76,6 @@ func checkScan(t *testing.T, c *ledis.Client, cmd string) { } -func checkRevScan(t *testing.T, c *ledis.Client, cmd string) { - if ay, err := ledis.Values(c.Do(cmd, "", "count", 5)); err != nil { - t.Fatal(err) - } else if len(ay) != 2 { - t.Fatal(len(ay)) - } else if n := ay[0].([]byte); string(n) != "5" { - t.Fatal(string(n)) - } else { - checkScanValues(t, ay[1], 9, 8, 7, 6, 5) - } - - if ay, err := ledis.Values(c.Do(cmd, "5", "count", 6)); err != nil { - t.Fatal(err) - } else if len(ay) != 2 { - t.Fatal(len(ay)) - } else if n := ay[0].([]byte); string(n) != "" { - t.Fatal(string(n)) - } else { - checkScanValues(t, ay[1], 4, 3, 2, 1, 0) - } - -} - func testKVScan(t *testing.T, c *ledis.Client) { for i := 0; i < 10; i++ { if _, err := c.Do("set", fmt.Sprintf("%d", i), []byte("value")); err != nil { @@ -106,50 +83,95 @@ func testKVScan(t *testing.T, c *ledis.Client) { } } - checkScan(t, c, "xscan") - checkRevScan(t, c, "xrevscan") + checkScan(t, c, "KV") } -func testHashScan(t *testing.T, c *ledis.Client) { +func testHashKeyScan(t *testing.T, c *ledis.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) } } - checkScan(t, c, "xhscan") - checkRevScan(t, c, "xhrevscan") + checkScan(t, c, "HASH") } -func testListScan(t *testing.T, c *ledis.Client) { +func testListKeyScan(t *testing.T, c *ledis.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) } } - checkScan(t, c, "xlscan") - checkRevScan(t, c, "xlrevscan") + checkScan(t, c, "LIST") } -func testZSetScan(t *testing.T, c *ledis.Client) { +func testZSetKeyScan(t *testing.T, c *ledis.Client) { for i := 0; i < 10; i++ { if _, err := c.Do("zadd", fmt.Sprintf("%d", i), i, []byte("value")); err != nil { t.Fatal(err) } } - checkScan(t, c, "zxscan") - checkRevScan(t, c, "zxrevscan") + checkScan(t, c, "ZSET") } -func testSetScan(t *testing.T, c *ledis.Client) { +func testSetKeyScan(t *testing.T, c *ledis.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) } } - checkScan(t, c, "xsscan") - checkRevScan(t, c, "xsrevscan") + checkScan(t, c, "SET") +} + +func TestHashScan(t *testing.T) { + c := getTestConn() + defer c.Close() + + key := "scan_hash" + c.Do("HMSET", key, "a", 1, "b", 2) + + if ay, err := ledis.Values(c.Do("XHSCAN", key, "")); err != nil { + t.Fatal(err) + } else if len(ay) != 2 { + t.Fatal(len(ay)) + } else { + checkScanValues(t, ay[1], "a", 1, "b", 2) + } +} + +func TestSetScan(t *testing.T) { + c := getTestConn() + defer c.Close() + + key := "scan_set" + c.Do("SADD", key, "a", "b") + + if ay, err := ledis.Values(c.Do("XSSCAN", key, "")); err != nil { + t.Fatal(err) + } else if len(ay) != 2 { + t.Fatal(len(ay)) + } else { + checkScanValues(t, ay[1], "a", "b") + } + +} + +func TestZSetScan(t *testing.T) { + c := getTestConn() + defer c.Close() + + key := "scan_zset" + c.Do("ZADD", key, 1, "a", 2, "b") + + if ay, err := ledis.Values(c.Do("XZSCAN", key, "")); err != nil { + t.Fatal(err) + } else if len(ay) != 2 { + t.Fatal(len(ay)) + } else { + checkScanValues(t, ay[1], "a", 1, "b", 2) + } + } diff --git a/server/cmd_set.go b/server/cmd_set.go index ae22bc5..b2ee2dc 100644 --- a/server/cmd_set.go +++ b/server/cmd_set.go @@ -262,14 +262,6 @@ func spersistCommand(c *client) error { return nil } -func sxscanCommand(c *client) error { - return xscanGeneric(c, c.db.SScan) -} - -func sxrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.SRevScan) -} - func xsexistsCommand(c *client) error { args := c.args if len(args) != 1 { @@ -301,10 +293,6 @@ func init() { register("sexpireat", sexpireAtCommand) register("sttl", sttlCommand) register("spersist", spersistCommand) - register("sxscan", sxscanCommand) - register("sxrevscan", sxrevscanCommand) - register("xsscan", sxscanCommand) - register("xsrevscan", sxrevscanCommand) register("xsexists", xsexistsCommand) } diff --git a/server/cmd_zset.go b/server/cmd_zset.go index ddeefbd..77d2db3 100644 --- a/server/cmd_zset.go +++ b/server/cmd_zset.go @@ -641,14 +641,6 @@ func zinterstoreCommand(c *client) error { return err } -func zxscanCommand(c *client) error { - return xscanGeneric(c, c.db.ZScan) -} - -func zxrevscanCommand(c *client) error { - return xscanGeneric(c, c.db.ZRevScan) -} - func zparseMemberRange(minBuf []byte, maxBuf []byte) (min []byte, max []byte, rangeType uint8, err error) { rangeType = store.RangeClose if strings.ToLower(hack.String(minBuf)) == "-" { @@ -815,9 +807,5 @@ func init() { register("zexpireat", zexpireAtCommand) register("zttl", zttlCommand) register("zpersist", zpersistCommand) - register("zxscan", zxscanCommand) - register("zxrevscan", zxrevscanCommand) - register("xzscan", zxscanCommand) - register("xzrevscan", zxrevscanCommand) register("xzexists", xzexistsCommand) } diff --git a/server/const.go b/server/const.go index dc55e24..9804ad7 100644 --- a/server/const.go +++ b/server/const.go @@ -2,6 +2,7 @@ package server import ( "errors" + "github.com/siddontang/ledisdb/ledis" ) var ( @@ -26,12 +27,11 @@ var ( ) const ( - KV = iota - LIST - HASH - SET - ZSET - BIT + KV ledis.DataType = ledis.KV + LIST = ledis.LIST + HASH = ledis.HASH + SET = ledis.SET + ZSET = ledis.ZSET ) const (