Merge branch 'develop'

This commit is contained in:
siddontang 2014-09-09 12:30:17 +08:00
commit da87fe0d5f
16 changed files with 156 additions and 96 deletions

View File

@ -12,7 +12,7 @@ LedisDB now supports multiple databases as backend to store data, you can test a
+ Supports transaction using LMDB or BotlDB.
+ Supports lua scripting.
+ Supports expiration and ttl.
+ Redis clients, like redis-cli, are supported directly.
+ Supports using redis-cli directly.
+ Multiple client API supports, including Go, Python, Lua(Openresty), C/C++, Node.js.
+ Easy to embed in your own Go application.
+ Restful API support, json/bson/msgpack output.

View File

@ -384,14 +384,14 @@ class Ledis(object):
"Removes an expiration on name"
return self.execute_command('PERSIST', name)
def scan(self, key="" , match=None, count=10):
def xscan(self, key="" , match=None, count=10):
pieces = [key]
if match is not None:
pieces.extend(["MATCH", match])
pieces.extend(["COUNT", count])
return self.execute_command("SCAN", *pieces)
return self.execute_command("XSCAN", *pieces)
def scan_iter(self, match=None, count=10):
key = ""
@ -475,8 +475,8 @@ class Ledis(object):
"Removes an expiration on ``name``"
return self.execute_command('LPERSIST', name)
def lscan(self, key="", match=None, count=10):
return self.scan_generic("LSCAN", key=key, match=match, count=count)
def lxscan(self, key="", match=None, count=10):
return self.scan_generic("LXSCAN", key=key, match=match, count=count)
#### SET COMMANDS ####
@ -575,8 +575,8 @@ class Ledis(object):
"Removes an expiration on name"
return self.execute_command('SPERSIST', name)
def sscan(self, key="", match=None, count = 10):
return self.scan_generic("SSCAN", key=key, match=match, count=count)
def sxscan(self, key="", match=None, count = 10):
return self.scan_generic("SXSCAN", key=key, match=match, count=count)
#### SORTED SET COMMANDS ####
@ -783,8 +783,8 @@ class Ledis(object):
scan_type = scan_type.upper()
return self.execute_command(scan_type, *pieces)
def zscan(self, key="", match=None, count=10):
return self.scan_generic("ZSCAN", key=key, match=match, count=count)
def zxscan(self, key="", match=None, count=10):
return self.scan_generic("ZXSCAN", key=key, match=match, count=count)
#### HASH COMMANDS ####
def hdel(self, name, *keys):
@ -878,8 +878,8 @@ class Ledis(object):
"Removes an expiration on name"
return self.execute_command('HPERSIST', name)
def hscan(self, key="", match=None, count=10):
return self.scan_generic("HSCAN", key=key, match=match, count=count)
def hxscan(self, key="", match=None, count=10):
return self.scan_generic("HXSCAN", key=key, match=match, count=count)
### BIT COMMANDS
@ -957,8 +957,8 @@ class Ledis(object):
"Removes an expiration on name"
return self.execute_command('BPERSIST', name)
def bscan(self, key="", match=None, count=10):
return self.scan_generic("BSCAN", key=key, match=match, count=count)
def bxscan(self, key="", match=None, count=10):
return self.scan_generic("BXSCAN", key=key, match=match, count=count)
def eval(self, script, keys, *args):
n = len(keys)

View File

@ -63,12 +63,12 @@ class TestOtherCommands(unittest.TestCase):
def check_keys(self, scan_type):
d = {
"scan": l.scan,
"sscan": l.sscan,
"lscan": l.lscan,
"hscan": l.hscan,
"zscan": l.zscan,
"bscan": l.bscan
"xscan": l.xscan,
"sxscan": l.sxscan,
"lxscan": l.lxscan,
"hxscan": l.hxscan,
"zxscan": l.zxscan,
"bxscan": l.bxscan
}
key, keys = d[scan_type]()
@ -82,40 +82,40 @@ class TestOtherCommands(unittest.TestCase):
assert set(keys) == set([b("b"), b("c")])
def test_scan(self):
def test_xscan(self):
d = {"a":1, "b":2, "c": 3}
l.mset(d)
self.check_keys("scan")
self.check_keys("xscan")
def test_lscan(self):
def test_lxscan(self):
l.rpush("a", 1)
l.rpush("b", 1)
l.rpush("c", 1)
self.check_keys("lscan")
self.check_keys("lxscan")
def test_hscan(self):
def test_hxscan(self):
l.hset("a", "hello", "world")
l.hset("b", "hello", "world")
l.hset("c", "hello", "world")
self.check_keys("hscan")
self.check_keys("hxscan")
def test_sscan(self):
def test_sxscan(self):
l.sadd("a", 1)
l.sadd("b", 2)
l.sadd("c", 3)
self.check_keys("sscan")
self.check_keys("sxscan")
def test_zscan(self):
def test_zxscan(self):
l.zadd("a", 1, "a")
l.zadd("b", 1, "a")
l.zadd("c", 1, "a")
self.check_keys("zscan")
self.check_keys("zxscan")
def test_bscan(self):
def test_bxscan(self):
l.bsetbit("a", 1, 1)
l.bsetbit("b", 1, 1)
l.bsetbit("c", 1, 1)
self.check_keys("bscan")
self.check_keys("bxscan")

View File

@ -20,7 +20,7 @@ module.exports = [
"bexpireat",
"bttl",
"bpersist",
"bscan",
"bxscan",
"hdel",
"hexists",
@ -40,7 +40,7 @@ module.exports = [
"hexpireat",
"httl",
"hpersist",
"hscan",
"hxscan",
"decr",
"decrby",
@ -58,7 +58,7 @@ module.exports = [
"expireat",
"ttl",
"persist",
"scan",
"xscan",
"lindex",
"llen",
@ -75,7 +75,7 @@ module.exports = [
"lexpireat",
"lttl",
"lpersist",
"lscan",
"lxscan",
"zadd",
"zcard",
@ -101,7 +101,7 @@ module.exports = [
"zexpireat",
"zttl",
"zpersist",
"zscan",
"zxscan",
"sadd",
@ -123,7 +123,7 @@ module.exports = [
"sexpireat",
"sttl",
"spersist",
"sscan",
"sxscan",
"begin",
"rollback",

View File

@ -40,7 +40,7 @@ local commands = {
"expire",
"expireat",
"persist",
"scan",
"xscan",
--[[hash]]
"hdel",
@ -61,7 +61,7 @@ local commands = {
"hexpireat",
"httl",
"hpersist",
"hscan",
"hxscan",
--[[list]]
"lindex",
@ -78,7 +78,7 @@ local commands = {
"lexpireat",
"lttl",
"lpersist",
"lscan",
"lxscan",
--[[zset]]
"zadd",
@ -102,7 +102,7 @@ local commands = {
"zexpireat",
"zttl",
"zpersist",
"zscan",
"zxscan",
--[[bit]]
"bget",
@ -116,7 +116,7 @@ local commands = {
"bexpireat",
"bttl",
"bpersist",
"bscan",
"bxscan",
--[[set]]
"sadd",
@ -138,7 +138,7 @@ local commands = {
"sexpireat",
"sttl",
"spersist",
"sscan",
"sxscan",
--[[server]]
"ping",

View File

@ -1,4 +1,4 @@
//This file was generated by .tools/generate_commands.py on Tue Sep 02 2014 22:27:45 +0800
//This file was generated by .tools/generate_commands.py on Tue Sep 09 2014 09:48:57 +0800
package main
var helpCommands = [][]string{
@ -12,9 +12,9 @@ var helpCommands = [][]string{
{"BMSETBIT", "key offset value [offset value ...]", "Bitmap"},
{"BOPT", "operation destkey key [key ...]", "Bitmap"},
{"BPERSIST", "key", "Bitmap"},
{"BSCAN", "key [MATCH match] [COUNT count]", "Bitmap"},
{"BSETBIT", "key offset value", "Bitmap"},
{"BTTL", "key", "Bitmap"},
{"BXSCAN", "key [MATCH match] [COUNT count]", "Bitmap"},
{"COMMIT", "-", "Transaction"},
{"DECR", "key", "KV"},
{"DECRBY", "key decrement", "KV"},
@ -44,10 +44,10 @@ var helpCommands = [][]string{
{"HMGET", "key field [field ...]", "Hash"},
{"HMSET", "key field value [field value ...]", "Hash"},
{"HPERSIST", "key", "Hash"},
{"HSCAN", "key [MATCH match] [COUNT count]", "Hash"},
{"HSET", "key field value", "Hash"},
{"HTTL", "key", "Hash"},
{"HVALS", "key", "Hash"},
{"HXSCAN", "key [MATCH match] [COUNT count]", "Hash"},
{"INCR", "key", "KV"},
{"INCRBY", "key increment", "KV"},
{"INFO", "[section]", "Server"},
@ -61,8 +61,8 @@ var helpCommands = [][]string{
{"LPOP", "key", "List"},
{"LPUSH", "key value [value ...]", "List"},
{"LRANGE", "key start stop", "List"},
{"LSCAN", "key [MATCH match] [COUNT count]", "List"},
{"LTTL", "key", "List"},
{"LXSCAN", "key [MATCH match] [COUNT count]", "List"},
{"MGET", "key [key ...]", "KV"},
{"MSET", "key value [key value ...]", "KV"},
{"PERSIST", "key", "KV"},
@ -71,7 +71,6 @@ var helpCommands = [][]string{
{"RPOP", "key", "List"},
{"RPUSH", "key value [value ...]", "List"},
{"SADD", "key member [member ...]", "Set"},
{"SCAN", "key [MATCH match] [COUNT count]", "KV"},
{"SCARD", "key", "Set"},
{"SCLEAR", "key", "Set"},
{"SCRIPT EXISTS", "script [script ...]", "Script"},
@ -92,12 +91,13 @@ var helpCommands = [][]string{
{"SMEMBERS", "key", "Set"},
{"SPERSIST", "key", "Set"},
{"SREM", "key member [member ...]", "Set"},
{"SSCAN", "key [MATCH match] [COUNT count]", "Set"},
{"STTL", "key", "Set"},
{"SUNION", "key [key ...]", "Set"},
{"SUNIONSTORE", "destination key [key ...]", "Set"},
{"SXSCAN", "key [MATCH match] [COUNT count]", "Set"},
{"SYNC", "index offset", "Replication"},
{"TTL", "key", "KV"},
{"XSCAN", "key [MATCH match] [COUNT count]", "KV"},
{"ZADD", "key score member [score member ...]", "ZSet"},
{"ZCARD", "key", "ZSet"},
{"ZCLEAR", "key", "ZSet"},
@ -117,8 +117,8 @@ var helpCommands = [][]string{
{"ZREVRANGE", "key start stop [WITHSCORES]", "ZSet"},
{"ZREVRANGEBYSCORE", "key max min [WITHSCORES][LIMIT offset count]", "ZSet"},
{"ZREVRANK", "key member", "ZSet"},
{"ZSCAN", "key [MATCH match] [COUNT count]", "ZSet"},
{"ZSCORE", "key member", "ZSet"},
{"ZTTL", "key", "ZSet"},
{"ZUNIONSTORE", "destkey numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]", "ZSet"},
{"ZXSCAN", "key [MATCH match] [COUNT count]", "ZSet"},
}

60
doc/DiffRedis.md Normal file
View File

@ -0,0 +1,60 @@
LedisDB is not Redis, so you can not use some Redis clients for LedisDB directly.
But LedisDB uses Redis protocol for communication and many APIs are same as Redis,
so you can easily write your own LedisDB client based on a Redis one.
Before you write a client, you must know some differences between LedisDB and Redis.
## Data Structure
LedisDB has no Strings data type but KV and Bitmap, any some Keys and Strings commands in Redis will only affect KV data, and "bit" commands affect Bitmap.
## Del
In Redis, `del` can delete all type data, like String, Hash, List, etc, but in LedisDB, `del` can only delete KV data. To delete other type data, you will use "clear" commands.
+ KV: `del`, `mdel`
+ Hash: `hclear`, `mhclear`
+ List: `lclear`, `mlclear`
+ Set: `sclear`, `msclear`
+ Zset: `zclear`, `mzclear`
+ Bitmap: `bclear`, `mbclear`
## Expire, Persist, and TTL
The same for Del.
+ KV: `expire`, `persist`, `ttl`
+ Hash: `hexpire`, `hpersist`, `httl`
+ List: `lexpire`, `lpersist`, `lttl`
+ Set: `sexpire`, `spersist`, `sttl`
+ Zset: `zexpire`, `zpersist`, `zttl`
+ Bitmap: `bexpire`, `bpersist`, `bttl`
## ZSet
ZSet only support int64 score, not double in Redis.
## Transaction
LedisDB supports ACID transaction using LMDB or BoltDB, maybe later it will support `multi`, `exec`, `discard`.
Transaction API:
+ `begin`
+ `commit`
+ `rollback`
## Scan
LedisDB supplies `xscan`, etc, to fetch data iteratively.
+ KV: `xscan`
+ Hash: `hxscan`
+ List: `lxscan`
+ Set: `sxscan`
+ Zset: `zxscan`
+ Bitmap: `bxscan`
Of course, LedisDB has not implemented all APIs in Redis, you can see full commands in commands.json, commands.doc or [wiki](https://github.com/siddontang/ledisdb/wiki/Commands).

View File

@ -528,37 +528,37 @@
"readonly": false
},
"SCAN": {
"XSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "KV",
"readonly": true
},
"HSCAN": {
"HXSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "Hash",
"readonly": true
},
"LSCAN": {
"LXSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "List",
"readonly": true
},
"SSCAN": {
"SXSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "Set",
"readonly": true
},
"ZSCAN": {
"ZXSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "ZSet",
"readonly": true
},
"BSCAN": {
"BXSCAN": {
"arguments": "key [MATCH match] [COUNT count]",
"group": "Bitmap",
"readonly": true

View File

@ -26,7 +26,7 @@ Table of Contents
- [EXPIREAT key timestamp](#expireat-key-timestamp)
- [TTL key](#ttl-key)
- [PERSIST key](#persist-key)
- [SCAN key [MATCH match] [COUNT count]](#scan-key-match-match-count-count)
- [XSCAN key [MATCH match] [COUNT count]](#xscan-key-match-match-count-count)
- [Hash](#hash)
- [HDEL key field [field ...]](#hdel-key-field-field-)
- [HEXISTS key field](#hexists-key-field)
@ -45,7 +45,7 @@ Table of Contents
- [HEXPIREAT key timestamp](#hexpireat-key-timestamp)
- [HTTL key](#httl-key)
- [HPERSIST key](#hpersist-key)
- [HSCAN key [MATCH match] [COUNT count]](#hscan-key-match-match-count-count)
- [HXSCAN key [MATCH match] [COUNT count]](#hxscan-key-match-match-count-count)
- [List](#list)
- [LINDEX key index](#lindex-key-index)
- [LLEN key](#llen-key)
@ -60,7 +60,7 @@ Table of Contents
- [LEXPIREAT key timestamp](#lexpireat-key-timestamp)
- [LTTL key](#lttl-key)
- [LPERSIST key](#lpersist-key)
- [LSCAN key [MATCH match] [COUNT count]](#lscan-key-match-match-count-count)
- [LXSCAN key [MATCH match] [COUNT count]](#lxscan-key-match-match-count-count)
- [Set](#set)
- [SADD key member [member ...]](#sadd-key-member-member-)
- [SCARD key](#scard-key)
@ -79,7 +79,7 @@ Table of Contents
- [SEXPIREAT key timestamp](#sexpireat-key-timestamp)
- [STTL key](#sttl-key)
- [SPERSIST key](#spersist-key)
- [SSCAN key [MATCH match] [COUNT count]](#sscan-key-match-match-count-count)
- [SXSCAN key [MATCH match] [COUNT count]](#sxscan-key-match-match-count-count)
- [ZSet](#zset)
- [ZADD key score member [score member ...]](#zadd-key-score-member-score-member-)
- [ZCARD key](#zcard-key)
@ -105,7 +105,7 @@ 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)
- [ZSCAN key [MATCH match] [COUNT count]](#zscan-key-match-match-count-count)
- [ZXSCAN key [MATCH match] [COUNT count]](#zxscan-key-match-match-count-count)
- [Bitmap](#bitmap)
- [BGET key](#bget-key)
- [BGETBIT key offset](#bgetbit-key-offset)
@ -117,7 +117,7 @@ Table of Contents
- [BEXPIREAT key timestamp](#bexpireat-key-timestamp)
- [BTTL key](#bttl-key)
- [BPERSIST key](#bpersist-key)
- [BSCAN key [MATCH match] [COUNT count]](#bscan-key-match-match-count-count)
- [BXSCAN key [MATCH match] [COUNT count]](#bxscan-key-match-match-count-count)
- [Replication](#replication)
- [SLAVEOF host port](#slaveof-host-port)
- [FULLSYNC](#fullsync)
@ -469,7 +469,7 @@ ledis> TTL mykey
(integer) -1
```
### SCAN key [MATCH match] [COUNT count]
### XSCAN key [MATCH match] [COUNT count]
Iterate KV keys incrementally.
@ -490,19 +490,19 @@ ledis>set b 2
OK
ledis>set c 3
OK
127.0.0.1:6380>scan ""
127.0.0.1:6380>xscan ""
1) ""
2) ["a" "b" "c"]
ledis>scan "" count 1
ledis>xscan "" count 1
1) "a"
2) ["a"]
ledis>scan "a" count 1
ledis>xscan "a" count 1
1) "b"
2) ["b"]
ledis>scan "b" count 1
ledis>xscan "b" count 1
1) "c"
2) ["c"]
ledis>scan "c" count 1
ledis>xscan "c" count 1
1) ""
2) []
```
@ -870,11 +870,11 @@ ledis> HPERSIST not_exists_key
(integer) 0
```
### HSCAN key [MATCH match] [COUNT count]
### HXSCAN key [MATCH match] [COUNT count]
Iterate Hash keys incrementally.
See [Scan](#scan-key-match-match-count-count) for more information.
See [XSCAN](#xscan-key-match-match-count-count) for more information.
## List
@ -1167,11 +1167,11 @@ ledis> LPERSIST b
(integer) 0
```
### LSCAN key [MATCH match] [COUNT count]
### LXSCAN key [MATCH match] [COUNT count]
Iterate list keys incrementally.
See [Scan](#scan-key-match-match-count-count) for more information.
See [XSCAN](#xscan-key-match-match-count-count) for more information.
## Set
@ -1595,11 +1595,11 @@ ledis> STTL key
(integer) -1
```
### SSCAN key [MATCH match] [COUNT count]
### SXSCAN key [MATCH match] [COUNT count]
Iterate Set keys incrementally.
See [Scan](#scan-key-match-match-count-count) for more information.
See [XSCAN](#xscan-key-match-match-count-count) for more information.
## ZSet
@ -2221,11 +2221,11 @@ ledis> ZRANGE out 0 -1 WITHSCORES
4) "10"
```
### ZSCAN key [MATCH match] [COUNT count]
### ZXSCAN key [MATCH match] [COUNT count]
Iterate ZSet keys incrementally.
See [Scan](#scan-key-match-match-count-count) for more information.
See [XSCAN](#xscan-key-match-match-count-count) for more information.
## Bitmap
@ -2387,11 +2387,11 @@ ledis> BCOUNT flag 5 6
(refer to [PERSIST](#persist-key) api for other types)
### BSCAN key [MATCH match] [COUNT count]
### BXSCAN key [MATCH match] [COUNT count]
Iterate Bitmap keys incrementally.
See [Scan](#scan-key-match-match-count-count) for more information.
See [XSCAN](#xscan-key-match-match-count-count) for more information.
## Replication

View File

@ -272,7 +272,7 @@ func bpersistCommand(c *client) error {
return nil
}
func bscanCommand(c *client) error {
func bxscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -305,5 +305,5 @@ func init() {
register("bexpireat", bexpireAtCommand)
register("bttl", bttlCommand)
register("bpersist", bpersistCommand)
register("bscan", bscanCommand)
register("bxscan", bxscanCommand)
}

View File

@ -292,7 +292,7 @@ func hpersistCommand(c *client) error {
return nil
}
func hscanCommand(c *client) error {
func hxscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -334,5 +334,5 @@ func init() {
register("hexpireat", hexpireAtCommand)
register("httl", httlCommand)
register("hpersist", hpersistCommand)
register("hscan", hscanCommand)
register("hxscan", hxscanCommand)
}

View File

@ -320,7 +320,7 @@ func parseScanArgs(c *client) (key []byte, match string, count int, err error) {
return
}
func scanCommand(c *client) error {
func xscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -358,5 +358,5 @@ func init() {
register("expireat", expireAtCommand)
register("ttl", ttlCommand)
register("persist", persistCommand)
register("scan", scanCommand)
register("xscan", xscanCommand)
}

View File

@ -228,7 +228,7 @@ func lpersistCommand(c *client) error {
return nil
}
func lscanCommand(c *client) error {
func lxscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -266,5 +266,5 @@ func init() {
register("lexpireat", lexpireAtCommand)
register("lttl", lttlCommand)
register("lpersist", lpersistCommand)
register("lscan", lscanCommand)
register("lxscan", lxscanCommand)
}

View File

@ -262,7 +262,7 @@ func spersistCommand(c *client) error {
return nil
}
func sscanCommand(c *client) error {
func sxscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -301,5 +301,5 @@ func init() {
register("sexpireat", sexpireAtCommand)
register("sttl", sttlCommand)
register("spersist", spersistCommand)
register("sscan", sscanCommand)
register("sxscan", sxscanCommand)
}

View File

@ -638,7 +638,7 @@ func zinterstoreCommand(c *client) error {
return err
}
func zscanCommand(c *client) error {
func zxscanCommand(c *client) error {
key, match, count, err := parseScanArgs(c)
if err != nil {
return err
@ -686,5 +686,5 @@ func init() {
register("zexpireat", zexpireAtCommand)
register("zttl", zttlCommand)
register("zpersist", zpersistCommand)
register("zscan", zscanCommand)
register("zxscan", zxscanCommand)
}

View File

@ -84,7 +84,7 @@ func testKVScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "scan")
checkScan(t, c, "xscan")
}
func testHashScan(t *testing.T, c *ledis.Client) {
@ -94,7 +94,7 @@ func testHashScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "hscan")
checkScan(t, c, "hxscan")
}
func testListScan(t *testing.T, c *ledis.Client) {
@ -104,7 +104,7 @@ func testListScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "lscan")
checkScan(t, c, "lxscan")
}
func testZSetScan(t *testing.T, c *ledis.Client) {
@ -114,7 +114,7 @@ func testZSetScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "zscan")
checkScan(t, c, "zxscan")
}
func testSetScan(t *testing.T, c *ledis.Client) {
@ -124,7 +124,7 @@ func testSetScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "sscan")
checkScan(t, c, "sxscan")
}
func testBitScan(t *testing.T, c *ledis.Client) {
@ -134,5 +134,5 @@ func testBitScan(t *testing.T, c *ledis.Client) {
}
}
checkScan(t, c, "bscan")
checkScan(t, c, "bxscan")
}