mirror of https://github.com/ledisdb/ledisdb.git
Merge branch 'set-feature' into develop
This commit is contained in:
commit
22161f91ba
|
@ -1,12 +1,12 @@
|
||||||
# LedisDB
|
# LedisDB
|
||||||
|
|
||||||
Ledisdb is a high performance NoSQL like Redis written by go. It supports some advanced data structure like kv, list, hash, zset, bitmap, and may be alternative for Redis.
|
Ledisdb is a high performance NoSQL like Redis written by go. It supports some advanced data structure like kv, list, hash, zset, bitmap,set, and may be alternative for Redis.
|
||||||
|
|
||||||
LedisDB now supports multiple databases as backend to store data, you can test and choose the proper one for you.
|
LedisDB now supports multiple databases as backend to store data, you can test and choose the proper one for you.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
+ Rich advanced data structure: KV, List, Hash, ZSet, Bitmap.
|
+ Rich advanced data structure: KV, List, Hash, ZSet, Bitmap, Set.
|
||||||
+ Stores lots of data, over the memory limit.
|
+ Stores lots of data, over the memory limit.
|
||||||
+ Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB, HyperLevelDB.
|
+ Various backend database to use: LevelDB, goleveldb, LMDB, RocksDB, BoltDB, HyperLevelDB.
|
||||||
+ Supports expiration and ttl.
|
+ Supports expiration and ttl.
|
||||||
|
|
|
@ -1,56 +1,96 @@
|
||||||
|
//This file was generated by ./generate.py on Fri Aug 15 2014 16:40:03 +0800
|
||||||
package main
|
package main
|
||||||
|
|
||||||
var helpCommands = [][]string{
|
var helpCommands = [][]string{
|
||||||
|
{"BCOUNT", "key [start end]", "Bitmap"},
|
||||||
|
{"BDELETE", "key", "ZSet"},
|
||||||
|
{"BEXPIRE", "key seconds", "Bitmap"},
|
||||||
|
{"BEXPIREAT", "key timestamp", "Bitmap"},
|
||||||
|
{"BGET", "key", "Bitmap"},
|
||||||
|
{"BGETBIT", "key offset", "Bitmap"},
|
||||||
|
{"BMSETBIT", "key offset value [offset value ...]", "Bitmap"},
|
||||||
|
{"BOPT", "operation destkey key [key ...]", "Bitmap"},
|
||||||
|
{"BPERSIST", "key", "Bitmap"},
|
||||||
|
{"BSETBIT", "key offset value", "Bitmap"},
|
||||||
|
{"BTTL", "key", "Bitmap"},
|
||||||
{"DECR", "key", "KV"},
|
{"DECR", "key", "KV"},
|
||||||
{"DECRBY", "key decrement", "KV"},
|
{"DECRBY", "key decrement", "KV"},
|
||||||
{"DEL", "key [key ...]", "KV"},
|
{"DEL", "key [key ...]", "KV"},
|
||||||
|
{"ECHO", "message", "Server"},
|
||||||
{"EXISTS", "key", "KV"},
|
{"EXISTS", "key", "KV"},
|
||||||
{"EXPIRE", "key seconds", "KV"},
|
{"EXPIRE", "key seconds", "KV"},
|
||||||
{"EXPIREAT", "key timestamp", "KV"},
|
{"EXPIREAT", "key timestamp", "KV"},
|
||||||
|
{"FULLSYNC", "-", "Replication"},
|
||||||
{"GET", "key", "KV"},
|
{"GET", "key", "KV"},
|
||||||
{"GETSET", " key value", "KV"},
|
{"GETSET", " key value", "KV"},
|
||||||
{"INCR", "key", "KV"},
|
{"HCLEAR", "key", "Hash"},
|
||||||
{"INCRBY", "key increment", "KV"},
|
|
||||||
{"MGET", "key [key ...]", "KV"},
|
|
||||||
{"MSET", "key value [key value ...]", "KV"},
|
|
||||||
{"SET", "key value", "KV"},
|
|
||||||
{"SETNX", "key value", "KV"},
|
|
||||||
{"TTL", "key", "KV"},
|
|
||||||
{"PERSIST", "key", "KV"},
|
|
||||||
{"HDEL", "key field [field ...]", "Hash"},
|
{"HDEL", "key field [field ...]", "Hash"},
|
||||||
{"HEXISTS", "key field", "Hash"},
|
{"HEXISTS", "key field", "Hash"},
|
||||||
|
{"HEXPIRE", "key seconds", "Hash"},
|
||||||
|
{"HEXPIREAT", "key timestamp", "Hash"},
|
||||||
{"HGET", "key field", "Hash"},
|
{"HGET", "key field", "Hash"},
|
||||||
{"HGETALL", "key", "Hash"},
|
{"HGETALL", "key", "Hash"},
|
||||||
{"HINCRBY", "key field increment", "Hash"},
|
{"HINCRBY", "key field increment", "Hash"},
|
||||||
{"HKEYS", "key", "Hash"},
|
{"HKEYS", "key", "Hash"},
|
||||||
{"HLEN", "key", "Hash"},
|
{"HLEN", "key", "Hash"},
|
||||||
|
{"HMCLEAR", "key [key ...]", "Hash"},
|
||||||
{"HMGET", "key field [field ...]", "Hash"},
|
{"HMGET", "key field [field ...]", "Hash"},
|
||||||
{"HMSET", "key field value [field value ...]", "Hash"},
|
{"HMSET", "key field value [field value ...]", "Hash"},
|
||||||
{"HSET", "key field value", "Hash"},
|
|
||||||
{"HVALS", "key", "Hash"},
|
|
||||||
{"HCLEAR", "key", "Hash"},
|
|
||||||
{"HMCLEAR", "key [key ...]", "Hash"},
|
|
||||||
{"HEXPIRE", "key seconds", "Hash"},
|
|
||||||
{"HEXPIREAT", "key timestamp", "Hash"},
|
|
||||||
{"HTTL", "key", "Hash"},
|
|
||||||
{"HPERSIST", "key", "Hash"},
|
{"HPERSIST", "key", "Hash"},
|
||||||
|
{"HSET", "key field value", "Hash"},
|
||||||
|
{"HTTL", "key", "Hash"},
|
||||||
|
{"HVALS", "key", "Hash"},
|
||||||
|
{"INCR", "key", "KV"},
|
||||||
|
{"INCRBY", "key increment", "KV"},
|
||||||
|
{"LCLEAR", "key", "List"},
|
||||||
|
{"LEXPIRE", "key seconds", "List"},
|
||||||
|
{"LEXPIREAT", "key timestamp", "List"},
|
||||||
{"LINDEX", "key index", "List"},
|
{"LINDEX", "key index", "List"},
|
||||||
{"LLEN", "key", "List"},
|
{"LLEN", "key", "List"},
|
||||||
|
{"LMCLEAR", "key [key ...]", "List"},
|
||||||
|
{"LPERSIST", "key", "List"},
|
||||||
{"LPOP", "key", "List"},
|
{"LPOP", "key", "List"},
|
||||||
{"LPUSH", "key value [value ...]", "List"},
|
{"LPUSH", "key value [value ...]", "List"},
|
||||||
{"LRANGE", "key start stop", "List"},
|
{"LRANGE", "key start stop", "List"},
|
||||||
|
{"LTTL", "key", "List"},
|
||||||
|
{"MGET", "key [key ...]", "KV"},
|
||||||
|
{"MSET", "key value [key value ...]", "KV"},
|
||||||
|
{"PERSIST", "key", "KV"},
|
||||||
|
{"PING", "-", "Server"},
|
||||||
{"RPOP", "key", "List"},
|
{"RPOP", "key", "List"},
|
||||||
{"RPUSH", "key value [value ...]", "List"},
|
{"RPUSH", "key value [value ...]", "List"},
|
||||||
{"LCLEAR", "key", "List"},
|
{"SADD", "key member [member ...]", "Set"},
|
||||||
{"LMCLEAR", "key [key ...]", "List"},
|
{"SCARD", "key", "Set"},
|
||||||
{"LEXPIRE", "key seconds", "List"},
|
{"SCLEAR", "key", "Set"},
|
||||||
{"LEXPIREAT", "key timestamp", "List"},
|
{"SDIFF", "key [key ...]", "Set"},
|
||||||
{"LTTL", "key", "List"},
|
{"SDIFFSTORE", "destination key [key ...]", "Set"},
|
||||||
{"LPERSIST", "key", "List"},
|
{"SELECT", "index", "Server"},
|
||||||
|
{"SET", "key value", "KV"},
|
||||||
|
{"SETNX", "key value", "KV"},
|
||||||
|
{"SEXPIRE", "key seconds", "Set"},
|
||||||
|
{"SEXPIREAT", "key timestamp", "Set"},
|
||||||
|
{"SINTER", "key [key ...]", "Set"},
|
||||||
|
{"SINTERSTORE", "destination key [key ...]", "Set"},
|
||||||
|
{"SISMEMBER", "key member", "Set"},
|
||||||
|
{"SLAVEOF", "host port", "Replication"},
|
||||||
|
{"SMCLEAR", "key [key ...]", "Set"},
|
||||||
|
{"SMEMBERS", "key", "Set"},
|
||||||
|
{"SPERSIST", "key", "Set"},
|
||||||
|
{"SREM", "key member [member ...]", "Set"},
|
||||||
|
{"STTL", "key", "Set"},
|
||||||
|
{"SUNION", "key [key ...]", "Set"},
|
||||||
|
{"SUNIONSTORE", "destination key [key ...]", "Set"},
|
||||||
|
{"SYNC", "index offset", "Replication"},
|
||||||
|
{"TTL", "key", "KV"},
|
||||||
{"ZADD", "key score member [score member ...]", "ZSet"},
|
{"ZADD", "key score member [score member ...]", "ZSet"},
|
||||||
{"ZCARD", "key", "ZSet"},
|
{"ZCARD", "key", "ZSet"},
|
||||||
|
{"ZCLEAR", "key", "ZSet"},
|
||||||
{"ZCOUNT", "key min max", "ZSet"},
|
{"ZCOUNT", "key min max", "ZSet"},
|
||||||
|
{"ZEXPIRE", "key seconds", "ZSet"},
|
||||||
|
{"ZEXPIREAT", "key timestamp", "ZSet"},
|
||||||
{"ZINCRBY", "key increment member", "ZSet"},
|
{"ZINCRBY", "key increment member", "ZSet"},
|
||||||
|
{"ZMCLEAR", "key [key ...]", "ZSet"},
|
||||||
|
{"ZPERSIST", "key", "ZSet"},
|
||||||
{"ZRANGE", "key start stop [WITHSCORES]", "ZSet"},
|
{"ZRANGE", "key start stop [WITHSCORES]", "ZSet"},
|
||||||
{"ZRANGEBYSCORE", "key min max [WITHSCORES] [LIMIT offset count]", "ZSet"},
|
{"ZRANGEBYSCORE", "key min max [WITHSCORES] [LIMIT offset count]", "ZSet"},
|
||||||
{"ZRANK", "key member", "ZSet"},
|
{"ZRANK", "key member", "ZSet"},
|
||||||
|
@ -61,27 +101,5 @@ var helpCommands = [][]string{
|
||||||
{"ZREVRANGEBYSCORE", "key max min [WITHSCORES][LIMIT offset count]", "ZSet"},
|
{"ZREVRANGEBYSCORE", "key max min [WITHSCORES][LIMIT offset count]", "ZSet"},
|
||||||
{"ZREVRANK", "key member", "ZSet"},
|
{"ZREVRANK", "key member", "ZSet"},
|
||||||
{"ZSCORE", "key member", "ZSet"},
|
{"ZSCORE", "key member", "ZSet"},
|
||||||
{"ZCLEAR", "key", "ZSet"},
|
|
||||||
{"ZMCLEAR", "key [key ...]", "ZSet"},
|
|
||||||
{"ZEXPIRE", "key seconds", "ZSet"},
|
|
||||||
{"ZEXPIREAT", "key timestamp", "ZSet"},
|
|
||||||
{"ZTTL", "key", "ZSet"},
|
{"ZTTL", "key", "ZSet"},
|
||||||
{"ZPERSIST", "key", "ZSet"},
|
|
||||||
{"BDELETE", "key", "ZSet"},
|
|
||||||
{"BGET", "key", "Bitmap"},
|
|
||||||
{"BGETBIT", "key offset", "Bitmap"},
|
|
||||||
{"BSETBIT", "key offset value", "Bitmap"},
|
|
||||||
{"BMSETBIT", "key offset value [offset value ...]", "Bitmap"},
|
|
||||||
{"BOPT", "operation destkey key [key ...]", "Bitmap"},
|
|
||||||
{"BCOUNT", "key [start end]", "Bitmap"},
|
|
||||||
{"BEXPIRE", "key seconds", "Bitmap"},
|
|
||||||
{"BEXPIREAT", "key timestamp", "Bitmap"},
|
|
||||||
{"BTTL", "key", "Bitmap"},
|
|
||||||
{"BPERSIST", "key", "Bitmap"},
|
|
||||||
{"SLAVEOF", "host port", "Replication"},
|
|
||||||
{"FULLSYNC", "-", "Replication"},
|
|
||||||
{"SYNC", "index offset", "Replication"},
|
|
||||||
{"PING", "-", "Server"},
|
|
||||||
{"ECHO", "message", "Server"},
|
|
||||||
{"SELECT", "index", "Server"},
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -310,6 +310,91 @@
|
||||||
"group": "Replication",
|
"group": "Replication",
|
||||||
"readonly": false
|
"readonly": false
|
||||||
},
|
},
|
||||||
|
"SADD" :{
|
||||||
|
"arguments": "key member [member ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SCARD": {
|
||||||
|
"arguments": "key",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SDIFF": {
|
||||||
|
"arguments": "key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SDIFFSTORE": {
|
||||||
|
"arguments": "destination key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SINTER": {
|
||||||
|
"arguments": "key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SINTERSTORE": {
|
||||||
|
"arguments": "destination key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SISMEMBER": {
|
||||||
|
"arguments": "key member",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SMEMBERS": {
|
||||||
|
"arguments": "key",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SREM": {
|
||||||
|
"arguments": "key member [member ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SUNION": {
|
||||||
|
"arguments": "key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SUNIONSTORE": {
|
||||||
|
"arguments": "destination key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SCLEAR": {
|
||||||
|
"arguments": "key",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SMCLEAR": {
|
||||||
|
"arguments": "key [key ...]",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SEXPIRE": {
|
||||||
|
"arguments": "key seconds",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"SEXPIREAT": {
|
||||||
|
"arguments": "key timestamp",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
|
"STTL": {
|
||||||
|
"arguments": "key",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": true
|
||||||
|
},
|
||||||
|
"SPERSIST": {
|
||||||
|
"arguments": "key",
|
||||||
|
"group": "Set",
|
||||||
|
"readonly": false
|
||||||
|
},
|
||||||
"TTL": {
|
"TTL": {
|
||||||
"arguments": "key",
|
"arguments": "key",
|
||||||
"group": "KV",
|
"group": "KV",
|
||||||
|
|
592
doc/commands.md
592
doc/commands.md
|
@ -58,6 +58,25 @@ Table of Contents
|
||||||
- [LEXPIREAT key timestamp](#lexpireat-key-timestamp)
|
- [LEXPIREAT key timestamp](#lexpireat-key-timestamp)
|
||||||
- [LTTL key](#lttl-key)
|
- [LTTL key](#lttl-key)
|
||||||
- [LPERSIST key](#lpersist-key)
|
- [LPERSIST key](#lpersist-key)
|
||||||
|
- [Set](#set)
|
||||||
|
- [SADD key member [member ...]](#sadd-key-member-member-)
|
||||||
|
- [SCARD key](#scard-key)
|
||||||
|
- [SDIFF key [key ...]](#sdiff-key-key-)
|
||||||
|
- [SDIFFSTORE destination key [key ...]](#sdiffstore-destination-key-key-)
|
||||||
|
- [SINTER key [key ...]](#sinter-key-key-)
|
||||||
|
- [SINTERSTORE destination key [key ...]](#sinterstore-destination-key-key-)
|
||||||
|
- [SISMEMBER key member](#sismember-key-member)
|
||||||
|
- [SMEMBERS key](#smembers-key)
|
||||||
|
- [SREM key member [member]](#srem-key-member-member-)
|
||||||
|
- [SUNION key [key ...]](#sunion-key-key-)
|
||||||
|
- [SUNIONSTORE destination key [key ...]](#sunionstore-destination-key-key-)
|
||||||
|
- [SCLEAR key](#sclear-key)
|
||||||
|
- [SMCLEAR key [key...]](#smclear-key-key)
|
||||||
|
- [SEXPIRE key seconds](#sexpire-key-seconds)
|
||||||
|
- [SEXPIREAT key timestamp](#sexpireat-key-timestamp)
|
||||||
|
- [STTL key](#sttl-key)
|
||||||
|
- [SPERSIST key](#spersist-key)
|
||||||
|
|
||||||
- [ZSet](#zset)
|
- [ZSet](#zset)
|
||||||
- [ZADD key score member [score member ...]](#zadd-key-score-member-score-member-)
|
- [ZADD key score member [score member ...]](#zadd-key-score-member-score-member-)
|
||||||
- [ZCARD key](#zcard-key)
|
- [ZCARD key](#zcard-key)
|
||||||
|
@ -665,7 +684,7 @@ ledis> HVALS myhash
|
||||||
|
|
||||||
### HCLEAR key
|
### HCLEAR key
|
||||||
|
|
||||||
Deletes the specified hash keys
|
Deletes the specified hash key
|
||||||
|
|
||||||
**Return value**
|
**Return value**
|
||||||
|
|
||||||
|
@ -1093,6 +1112,427 @@ ledis> LPERSIST b
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Set
|
||||||
|
|
||||||
|
### SADD key member [member ...]
|
||||||
|
Add the specified members to the set stored at key. Specified members that are already a member of this set are ignored. If key does not exist, a new set is created before adding the specified members.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of elements that were added to the set, not including all the elements already present into the set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset world
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 0
|
||||||
|
ledis> SMEMBERS myset
|
||||||
|
1) "hello"
|
||||||
|
2) "world"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SCARD key
|
||||||
|
|
||||||
|
Returns the set cardinality (number of elements) of the set stored at key.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the cardinality (number of elements) of the set, or 0 if key does not exist.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset world
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 0
|
||||||
|
ledis> SCARD myset
|
||||||
|
(integer) 2
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SDIFF key [key ...]
|
||||||
|
Returns the members of the set resulting from the difference between the first set and all the successive sets.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
key1 = {a,b,c,d}
|
||||||
|
key2 = {c}
|
||||||
|
key3 = {a,c,e}
|
||||||
|
SDIFF key1 key2 key3 = {b,d}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keys that do not exist are considered to be empty sets.
|
||||||
|
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
bulk: list with members of the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key1 a b c
|
||||||
|
(integer) 3
|
||||||
|
ledis> SADD key2 c d e
|
||||||
|
(integer) 3
|
||||||
|
ledis> SDIFF key1 key2
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
ledis> SDIFF key2 key1
|
||||||
|
1) "d"
|
||||||
|
2) "e"
|
||||||
|
```
|
||||||
|
|
||||||
|
### SDIFFSTORE destination key [key ...]
|
||||||
|
This command is equal to `SDIFF`, but instead of returning the resulting set, it is stored in destination.
|
||||||
|
If destination already exists, it is overwritten.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of elements in the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key1 a b c
|
||||||
|
(integer) 3
|
||||||
|
ledis> SADD key2 c d e
|
||||||
|
(integer) 3
|
||||||
|
ledis> SDIFF key1 key2
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
ledis> SDIFFSTORE key key1 key2
|
||||||
|
(integer) 2
|
||||||
|
ledis> SMEMBERS key
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
```
|
||||||
|
|
||||||
|
### SINTER key [key ...]
|
||||||
|
|
||||||
|
Returns the members of the set resulting from the intersection of all the given sets.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
key1 = {a,b,c,d}
|
||||||
|
key2 = {c}
|
||||||
|
key3 = {a,c,e}
|
||||||
|
SINTER key1 key2 key3 = {c}
|
||||||
|
```
|
||||||
|
|
||||||
|
Keys that do not exist are considered to be empty sets. With one of the keys being an empty set, the resulting set is also empty (since set intersection with an empty set always results in an empty set).
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
bulk: list with members of the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key1 a b c
|
||||||
|
(integer) 3
|
||||||
|
ledis> SADD key2 c d e
|
||||||
|
(integer) 3
|
||||||
|
ledis> SINTER key1 key2
|
||||||
|
1) "c"
|
||||||
|
ledis> SINTER key2 key_empty
|
||||||
|
(nil)
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SINTERSTORE destination key [key ...]
|
||||||
|
|
||||||
|
This command is equal to `SINTER`, but instead of returning the resulting set, it is stored in destination.
|
||||||
|
If destination already exists, it is overwritten.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of elements in the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key1 a b c
|
||||||
|
(integer) 3
|
||||||
|
ledis> SADD key2 c d e
|
||||||
|
(integer) 3
|
||||||
|
ledis> SINTERSTORE key key1 key2
|
||||||
|
(integer) 1
|
||||||
|
ledis> SMEMBERS key
|
||||||
|
1) "c"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SISMEMBER key member
|
||||||
|
Returns if member is a member of the set stored at key.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
Int64 reply, specifically:
|
||||||
|
|
||||||
|
- 1 if the element is a member of the set.
|
||||||
|
- 0 if the element is not a member of the set, or if key does not exist.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 1
|
||||||
|
ledis> SISMEMBER myset hello
|
||||||
|
(integer) 1
|
||||||
|
ledis> SISMEMBER myset hell
|
||||||
|
(integer) 0
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMEMBERS key
|
||||||
|
Returns all the members of the set value stored at key.
|
||||||
|
This has the same effect as running `SINTER` with one argument key.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
bulk: all elements of the set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD myset hello
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset world
|
||||||
|
(integer) 1
|
||||||
|
ledis> SMEMBERS myset
|
||||||
|
1) "hello"
|
||||||
|
2) "world"
|
||||||
|
```
|
||||||
|
|
||||||
|
### SREM key member [member ...]
|
||||||
|
|
||||||
|
Remove the specified members from the set stored at key. Specified members that are not a member of this set are ignored. If key does not exist, it is treated as an empty set and this command returns 0.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of members that were removed from the set, not including non existing members.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD myset one
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset two
|
||||||
|
(integer) 1
|
||||||
|
ledis> SADD myset three
|
||||||
|
(integer) 1
|
||||||
|
ledis> SREM myset one
|
||||||
|
(integer) 1
|
||||||
|
ledis> SREM myset four
|
||||||
|
(integer) 0
|
||||||
|
ledis> SMEMBERS myset
|
||||||
|
1) "three"
|
||||||
|
2) "two"
|
||||||
|
```
|
||||||
|
|
||||||
|
### SUNION key [key ...]
|
||||||
|
|
||||||
|
Returns the members of the set resulting from the union of all the given sets.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
key1 = {a,b,c,d}
|
||||||
|
key2 = {c}
|
||||||
|
key3 = {a,c,e}
|
||||||
|
SUNION key1 key2 key3 = {a,b,c,d,e}
|
||||||
|
```
|
||||||
|
Keys that do not exist are considered to be empty sets.
|
||||||
|
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
bulk: list with members of the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SMEMBERS key1
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
3) "c"
|
||||||
|
ledis> SMEMBERS key2
|
||||||
|
1) "c"
|
||||||
|
2) "d"
|
||||||
|
3) "e"
|
||||||
|
ledis> SUNION key1 key2
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
3) "c"
|
||||||
|
4) "d"
|
||||||
|
5) "e"
|
||||||
|
```
|
||||||
|
|
||||||
|
### SUNIONSTORE destination key [key]
|
||||||
|
|
||||||
|
This command is equal to SUNION, but instead of returning the resulting set, it is stored in destination.
|
||||||
|
If destination already exists, it is overwritten.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of elements in the resulting set.
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SMEMBERS key1
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
3) "c"
|
||||||
|
ledis> SMEMBERS key2
|
||||||
|
1) "c"
|
||||||
|
2) "d"
|
||||||
|
3) "e"
|
||||||
|
ledis> SUNIONSTORE key key1 key2
|
||||||
|
(integer) 5
|
||||||
|
ledis> SMEMBERS key
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
3) "c"
|
||||||
|
4) "d"
|
||||||
|
5) "e"
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SCLEAR key
|
||||||
|
|
||||||
|
Deletes the specified set key
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of fields in the hash stored at key
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SMEMBERS key
|
||||||
|
1) "a"
|
||||||
|
2) "b"
|
||||||
|
3) "c"
|
||||||
|
4) "d"
|
||||||
|
5) "e"
|
||||||
|
ledis> SCLEAR key
|
||||||
|
(integer) 5
|
||||||
|
```
|
||||||
|
|
||||||
|
### SMCLEAR key [key ...]
|
||||||
|
|
||||||
|
Deletes the specified set keys.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: the number of input keys
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SMCLEAR key1 key2
|
||||||
|
(integer) 2
|
||||||
|
ledis> SMCLEAR em1 em2
|
||||||
|
(integer) 2
|
||||||
|
```
|
||||||
|
|
||||||
|
### SEXPIRE key seconds
|
||||||
|
|
||||||
|
Sets a set key’s time to live in seconds, like expire similarly.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64:
|
||||||
|
|
||||||
|
- 1 if the timeout was set
|
||||||
|
- 0 if key does not exist or the timeout could not be set
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key 1 2
|
||||||
|
(integer) 2
|
||||||
|
ledis> SEXPIRE key 100
|
||||||
|
(integer) 1
|
||||||
|
ledis> STTL key
|
||||||
|
(integer) 95
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SEXPIREAT key timestamp
|
||||||
|
|
||||||
|
Sets the expiration for a set key as a unix timestamp, like expireat similarly.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64:
|
||||||
|
|
||||||
|
- 1 if the timeout was set
|
||||||
|
- 0 if key does not exist or the timeout could not be set
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key 1 2
|
||||||
|
(integer) 2
|
||||||
|
ledis> SEXPIREAT key 1408094999
|
||||||
|
(integer) 1
|
||||||
|
ledis> STTL key
|
||||||
|
(integer) 908
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### STTL key
|
||||||
|
|
||||||
|
Returns the remaining time to live of a key that has a timeout. If the key was not set a timeout, -1 returns.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64: TTL in seconds
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SADD key 1 2
|
||||||
|
(integer) 2
|
||||||
|
ledis> SEXPIREAT key 1408094999
|
||||||
|
(integer) 1
|
||||||
|
ledis> STTL key
|
||||||
|
(integer) 908
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### SPERSIST key
|
||||||
|
Remove the expiration from a set key, like persist similarly. Remove the existing timeout on key.
|
||||||
|
|
||||||
|
**Return value**
|
||||||
|
|
||||||
|
int64:
|
||||||
|
|
||||||
|
- 1 if the timeout was removed
|
||||||
|
- 0 if key does not exist or does not have an timeout
|
||||||
|
|
||||||
|
**Examples**
|
||||||
|
|
||||||
|
```
|
||||||
|
ledis> SEXPIREAT key 1408094999
|
||||||
|
(integer) 1
|
||||||
|
ledis> STTL key
|
||||||
|
(integer) 908
|
||||||
|
ledis> SPERSIST key
|
||||||
|
(integer) 1
|
||||||
|
ledis> STTL key
|
||||||
|
(integer) -1
|
||||||
|
```
|
||||||
|
|
||||||
## ZSet
|
## ZSet
|
||||||
|
|
||||||
### ZADD key score member [score member ...]
|
### ZADD key score member [score member ...]
|
||||||
|
@ -1114,13 +1554,13 @@ The number of elements added to the sorted sets, **not** including elements alre
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 1 'uno'
|
ledis> ZADD myzset 1 'uno'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two' 3 'three'
|
ledis> ZADD myzset 2 'two' 3 'three'
|
||||||
(integer) 2
|
(integer) 2
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "1"
|
2) "1"
|
||||||
3) "uno"
|
3) "uno"
|
||||||
|
@ -1141,13 +1581,13 @@ int64: the cardinality (number of elements) of the sorted set, or `0` if key doe
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
edis > ZADD myset 1 'one'
|
edis > ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 1 'uno'
|
ledis> ZADD myzset 1 'uno'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two' 3 'three'
|
ledis> ZADD myzset 2 'two' 3 'three'
|
||||||
(integer) 2
|
(integer) 2
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "1"
|
2) "1"
|
||||||
3) "uno"
|
3) "uno"
|
||||||
|
@ -1156,7 +1596,7 @@ ledis> ZRANGE myset 0 -1 WITHSCORES
|
||||||
6) "2"
|
6) "2"
|
||||||
7) "three"
|
7) "three"
|
||||||
8) "3"
|
8) "3"
|
||||||
ledis> ZCARD myset
|
ledis> ZCARD myzset
|
||||||
(integer) 4
|
(integer) 4
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1171,13 +1611,13 @@ int64: the number of elements in the specified score range.
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 1 'uno'
|
ledis> ZADD myzset 1 'uno'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two' 3 'three'
|
ledis> ZADD myzset 2 'two' 3 'three'
|
||||||
(integer) 2
|
(integer) 2
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "1"
|
2) "1"
|
||||||
3) "uno"
|
3) "uno"
|
||||||
|
@ -1186,9 +1626,9 @@ ledis> ZRANGE myset 0 -1 WITHSCORES
|
||||||
6) "2"
|
6) "2"
|
||||||
7) "three"
|
7) "three"
|
||||||
8) "3"
|
8) "3"
|
||||||
ledis> ZCOUNT myset -inf +inf
|
ledis> ZCOUNT myzset -inf +inf
|
||||||
(integer) 4
|
(integer) 4
|
||||||
ledis> ZCOUNT myset (1 3
|
ledis> ZCOUNT myzset (1 3
|
||||||
(integer) 2
|
(integer) 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1205,13 +1645,13 @@ bulk: the new score of member (an int64 number), represented as string.
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two'
|
ledis> ZADD myzset 2 'two'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZINCRBY myset 2 'one'
|
ledis> ZINCRBY myzset 2 'one'
|
||||||
3
|
3
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "two"
|
1) "two"
|
||||||
2) "2"
|
2) "2"
|
||||||
3) "one"
|
3) "one"
|
||||||
|
@ -1228,19 +1668,19 @@ array: list of elements in the specified range (optionally with their scores).
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two'
|
ledis> ZADD myzset 2 'two'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 3 'three'
|
ledis> ZADD myzset 3 'three'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZRANGE myset 0 -1
|
ledis> ZRANGE myzset 0 -1
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "two"
|
2) "two"
|
||||||
3) "three"
|
3) "three"
|
||||||
ledis> ZRANGE myset 2 3
|
ledis> ZRANGE myzset 2 3
|
||||||
1) "three"
|
1) "three"
|
||||||
ledis> ZRANGE myset -2 -1
|
ledis> ZRANGE myzset -2 -1
|
||||||
1) "two"
|
1) "two"
|
||||||
2) "three"
|
2) "three"
|
||||||
```
|
```
|
||||||
|
@ -1340,16 +1780,16 @@ The number of members removed from the sorted set, not including non existing me
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one 2 two 3 three 4 four
|
ledis> ZADD myzset 1 one 2 two 3 three 4 four
|
||||||
(integer) 3
|
(integer) 3
|
||||||
ledis> ZRANGE myset 0 -1
|
ledis> ZRANGE myzset 0 -1
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "two"
|
2) "two"
|
||||||
3) "three"
|
3) "three"
|
||||||
4) "four"
|
4) "four"
|
||||||
ledis> ZREM myset three
|
ledis> ZREM myzset three
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZREM myset one four three
|
ledis> ZREM myzset one four three
|
||||||
(integer) 2
|
(integer) 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1363,11 +1803,11 @@ int64: the number of elements removed.
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one 2 two 3 three 4 four
|
ledis> ZADD myzset 1 one 2 two 3 three 4 four
|
||||||
(integer) 3
|
(integer) 3
|
||||||
ledis> ZREMRANGEBYRANK myset 0 2
|
ledis> ZREMRANGEBYRANK myzset 0 2
|
||||||
(integer) 3
|
(integer) 3
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "four"
|
1) "four"
|
||||||
2) "4"
|
2) "4"
|
||||||
```
|
```
|
||||||
|
@ -1383,11 +1823,11 @@ int64: the number of elements removed.
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one 2 two 3 three 4 four
|
ledis> ZADD myzset 1 one 2 two 3 three 4 four
|
||||||
(integer) 4
|
(integer) 4
|
||||||
ledis> ZREMRANGEBYSCORE myset -inf (2
|
ledis> ZREMRANGEBYSCORE myzset -inf (2
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZRANGE myset 0 -1 WITHSCORES
|
ledis> ZRANGE myzset 0 -1 WITHSCORES
|
||||||
1) "two"
|
1) "two"
|
||||||
2) "2"
|
2) "2"
|
||||||
3) "three"
|
3) "three"
|
||||||
|
@ -1407,9 +1847,9 @@ array: list of elements in the specified range (optionally with their scores).
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one 2 two 3 three 4 four
|
ledis> ZADD myzset 1 one 2 two 3 three 4 four
|
||||||
(integer) 4
|
(integer) 4
|
||||||
ledis> ZREVRANGE myset 0 -1
|
ledis> ZREVRANGE myzset 0 -1
|
||||||
1) "four"
|
1) "four"
|
||||||
2) "three"
|
2) "three"
|
||||||
3) "two"
|
3) "two"
|
||||||
|
@ -1428,21 +1868,21 @@ array: list of elements in the specified score range (optionally with their scor
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one 2 two 3 three 4 four
|
ledis> ZADD myzset 1 one 2 two 3 three 4 four
|
||||||
(integer) 4
|
(integer) 4
|
||||||
ledis> ZREVRANGEBYSCORE myset +inf -inf
|
ledis> ZREVRANGEBYSCORE myzset +inf -inf
|
||||||
1) "four"
|
1) "four"
|
||||||
2) "three"
|
2) "three"
|
||||||
3) "two"
|
3) "two"
|
||||||
4) "one"
|
4) "one"
|
||||||
ledis> ZREVRANGEBYSCORE myset 2 1
|
ledis> ZREVRANGEBYSCORE myzset 2 1
|
||||||
1) "two"
|
1) "two"
|
||||||
2) "one"
|
2) "one"
|
||||||
ledis> ZREVRANGEBYSCORE myset 2 (1
|
ledis> ZREVRANGEBYSCORE myzset 2 (1
|
||||||
1) "two"
|
1) "two"
|
||||||
ledis> ZREVRANGEBYSCORE myset (2 (1
|
ledis> ZREVRANGEBYSCORE myzset (2 (1
|
||||||
(empty list or set)
|
(empty list or set)
|
||||||
ledis> ZREVRANGEBYSCORE myset +inf -inf WITHSCORES LIMIT 1 2
|
ledis> ZREVRANGEBYSCORE myzset +inf -inf WITHSCORES LIMIT 1 2
|
||||||
1) "three"
|
1) "three"
|
||||||
2) "3"
|
2) "3"
|
||||||
3) "two"
|
3) "two"
|
||||||
|
@ -1462,13 +1902,13 @@ Use ZRANK to get the rank of an element with the scores ordered from low to high
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 one
|
ledis> ZADD myzset 1 one
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 two
|
ledis> ZADD myzset 2 two
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZREVRANK myset one
|
ledis> ZREVRANK myzset one
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZREVRANK myset three
|
ledis> ZREVRANK myzset three
|
||||||
(nil)
|
(nil)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1484,9 +1924,9 @@ bulk: the score of member (an `int64` number), represented as string.
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZSCORE myset 'one'
|
ledis> ZSCORE myzset 'one'
|
||||||
1
|
1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1500,17 +1940,17 @@ int64: the number of members in the zset stored at key
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 2 'two'
|
ledis> ZADD myzset 2 'two'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset 3 'three'
|
ledis> ZADD myzset 3 'three'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZRANGE myset 0 -1
|
ledis> ZRANGE myzset 0 -1
|
||||||
1) "one"
|
1) "one"
|
||||||
2) "two"
|
2) "two"
|
||||||
3) "three"
|
3) "three"
|
||||||
ledis> ZCLEAR myset
|
ledis> ZCLEAR myzset
|
||||||
(integer) 3
|
(integer) 3
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1524,11 +1964,11 @@ int64: the number of input keys
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset1 1 'one'
|
ledis> ZADD myzset1 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZADD myset2 2 'two'
|
ledis> ZADD myzset2 2 'two'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZMCLEAR myset1 myset2
|
ledis> ZMCLEAR myzset1 myzset2
|
||||||
(integer) 2
|
(integer) 2
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1547,17 +1987,17 @@ int64:
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZEXPIRE myset 100
|
ledis> ZEXPIRE myzset 100
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL myset
|
ledis> ZTTL myzset
|
||||||
(integer) 97
|
(integer) 97
|
||||||
ledis> ZPERSIST myset
|
ledis> ZPERSIST myzset
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL mset
|
ledis> ZTTL mset
|
||||||
(integer) -1
|
(integer) -1
|
||||||
ledis> ZEXPIRE myset1 100
|
ledis> ZEXPIRE myzset1 100
|
||||||
(integer) 0
|
(integer) 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1574,17 +2014,17 @@ int64:
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZEXPIREAT myset 1404149999
|
ledis> ZEXPIREAT myzset 1404149999
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL myset
|
ledis> ZTTL myzset
|
||||||
(integer) 7155
|
(integer) 7155
|
||||||
ledis> ZPERSIST myset
|
ledis> ZPERSIST myzset
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL mset
|
ledis> ZTTL mset
|
||||||
(integer) -1
|
(integer) -1
|
||||||
ledis> ZEXPIREAT myset1 1404149999
|
ledis> ZEXPIREAT myzset1 1404149999
|
||||||
(integer) 0
|
(integer) 0
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1599,13 +2039,13 @@ int64: TTL in seconds
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZEXPIRE myset 100
|
ledis> ZEXPIRE myzset 100
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL myset
|
ledis> ZTTL myzset
|
||||||
(integer) 97
|
(integer) 97
|
||||||
ledis> ZTTL myset2
|
ledis> ZTTL myzset2
|
||||||
(integer) -1
|
(integer) -1
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -1622,13 +2062,13 @@ int64:
|
||||||
**Examples**
|
**Examples**
|
||||||
|
|
||||||
```
|
```
|
||||||
ledis> ZADD myset 1 'one'
|
ledis> ZADD myzset 1 'one'
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZEXPIRE myset 100
|
ledis> ZEXPIRE myzset 100
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL myset
|
ledis> ZTTL myzset
|
||||||
(integer) 97
|
(integer) 97
|
||||||
ledis> ZPERSIST myset
|
ledis> ZPERSIST myzset
|
||||||
(integer) 1
|
(integer) 1
|
||||||
ledis> ZTTL mset
|
ledis> ZTTL mset
|
||||||
(integer) -1
|
(integer) -1
|
||||||
|
|
|
@ -16,6 +16,8 @@ const (
|
||||||
ZScoreType byte = 8
|
ZScoreType byte = 8
|
||||||
BitType byte = 9
|
BitType byte = 9
|
||||||
BitMetaType byte = 10
|
BitMetaType byte = 10
|
||||||
|
SetType byte = 11
|
||||||
|
SSizeType byte = 12
|
||||||
|
|
||||||
maxDataType byte = 100
|
maxDataType byte = 100
|
||||||
|
|
||||||
|
@ -35,6 +37,8 @@ var (
|
||||||
ZScoreType: "zscore",
|
ZScoreType: "zscore",
|
||||||
BitType: "bit",
|
BitType: "bit",
|
||||||
BitMetaType: "bitmeta",
|
BitMetaType: "bitmeta",
|
||||||
|
SetType: "set",
|
||||||
|
SSizeType: "ssize",
|
||||||
ExpTimeType: "exptime",
|
ExpTimeType: "exptime",
|
||||||
ExpMetaType: "expmeta",
|
ExpMetaType: "expmeta",
|
||||||
}
|
}
|
||||||
|
@ -48,6 +52,7 @@ var (
|
||||||
errKeySize = errors.New("invalid key size")
|
errKeySize = errors.New("invalid key size")
|
||||||
errValueSize = errors.New("invalid value size")
|
errValueSize = errors.New("invalid value size")
|
||||||
errHashFieldSize = errors.New("invalid hash field size")
|
errHashFieldSize = errors.New("invalid hash field size")
|
||||||
|
errSetMemberSize = errors.New("invalid set member size")
|
||||||
errZSetMemberSize = errors.New("invalid zset member size")
|
errZSetMemberSize = errors.New("invalid zset member size")
|
||||||
errExpireValue = errors.New("invalid expire value")
|
errExpireValue = errors.New("invalid expire value")
|
||||||
)
|
)
|
||||||
|
@ -65,6 +70,9 @@ const (
|
||||||
//max zset member size
|
//max zset member size
|
||||||
MaxZSetMemberSize int = 1024
|
MaxZSetMemberSize int = 1024
|
||||||
|
|
||||||
|
//max set member size
|
||||||
|
MaxSetMemberSize int = 1024
|
||||||
|
|
||||||
//max value size
|
//max value size
|
||||||
MaxValueSize int = 10 * 1024 * 1024
|
MaxValueSize int = 10 * 1024 * 1024
|
||||||
)
|
)
|
||||||
|
|
|
@ -21,6 +21,7 @@ type DB struct {
|
||||||
hashTx *tx
|
hashTx *tx
|
||||||
zsetTx *tx
|
zsetTx *tx
|
||||||
binTx *tx
|
binTx *tx
|
||||||
|
setTx *tx
|
||||||
}
|
}
|
||||||
|
|
||||||
type Ledis struct {
|
type Ledis struct {
|
||||||
|
@ -88,6 +89,7 @@ func newDB(l *Ledis, index uint8) *DB {
|
||||||
d.hashTx = newTx(l)
|
d.hashTx = newTx(l)
|
||||||
d.zsetTx = newTx(l)
|
d.zsetTx = newTx(l)
|
||||||
d.binTx = newTx(l)
|
d.binTx = newTx(l)
|
||||||
|
d.setTx = newTx(l)
|
||||||
|
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ func (db *DB) FlushAll() (drop int64, err error) {
|
||||||
db.lFlush,
|
db.lFlush,
|
||||||
db.hFlush,
|
db.hFlush,
|
||||||
db.zFlush,
|
db.zFlush,
|
||||||
db.bFlush}
|
db.bFlush,
|
||||||
|
db.sFlush}
|
||||||
|
|
||||||
for _, flush := range all {
|
for _, flush := range all {
|
||||||
if n, e := flush(); e != nil {
|
if n, e := flush(); e != nil {
|
||||||
|
|
|
@ -0,0 +1,609 @@
|
||||||
|
package ledis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
|
"github.com/siddontang/ledisdb/store"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
var errSetKey = errors.New("invalid set key")
|
||||||
|
var errSSizeKey = errors.New("invalid ssize key")
|
||||||
|
|
||||||
|
const (
|
||||||
|
setStartSep byte = ':'
|
||||||
|
setStopSep byte = setStartSep + 1
|
||||||
|
UnionType byte = 51
|
||||||
|
DiffType byte = 52
|
||||||
|
InterType byte = 53
|
||||||
|
)
|
||||||
|
|
||||||
|
func checkSetKMSize(key []byte, member []byte) error {
|
||||||
|
if len(key) > MaxKeySize || len(key) == 0 {
|
||||||
|
return errKeySize
|
||||||
|
} else if len(member) > MaxSetMemberSize || len(member) == 0 {
|
||||||
|
return errSetMemberSize
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sEncodeSizeKey(key []byte) []byte {
|
||||||
|
buf := make([]byte, len(key)+2)
|
||||||
|
|
||||||
|
buf[0] = db.index
|
||||||
|
buf[1] = SSizeType
|
||||||
|
|
||||||
|
copy(buf[2:], key)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sDecodeSizeKey(ek []byte) ([]byte, error) {
|
||||||
|
if len(ek) < 2 || ek[0] != db.index || ek[1] != SSizeType {
|
||||||
|
return nil, errSSizeKey
|
||||||
|
}
|
||||||
|
|
||||||
|
return ek[2:], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sEncodeSetKey(key []byte, member []byte) []byte {
|
||||||
|
buf := make([]byte, len(key)+len(member)+1+1+2+1)
|
||||||
|
|
||||||
|
pos := 0
|
||||||
|
buf[pos] = db.index
|
||||||
|
pos++
|
||||||
|
buf[pos] = SetType
|
||||||
|
pos++
|
||||||
|
|
||||||
|
binary.BigEndian.PutUint16(buf[pos:], uint16(len(key)))
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
copy(buf[pos:], key)
|
||||||
|
pos += len(key)
|
||||||
|
|
||||||
|
buf[pos] = setStartSep
|
||||||
|
pos++
|
||||||
|
copy(buf[pos:], member)
|
||||||
|
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sDecodeSetKey(ek []byte) ([]byte, []byte, error) {
|
||||||
|
if len(ek) < 5 || ek[0] != db.index || ek[1] != SetType {
|
||||||
|
return nil, nil, errSetKey
|
||||||
|
}
|
||||||
|
|
||||||
|
pos := 2
|
||||||
|
keyLen := int(binary.BigEndian.Uint16(ek[pos:]))
|
||||||
|
pos += 2
|
||||||
|
|
||||||
|
if keyLen+5 > len(ek) {
|
||||||
|
return nil, nil, errSetKey
|
||||||
|
}
|
||||||
|
|
||||||
|
key := ek[pos : pos+keyLen]
|
||||||
|
pos += keyLen
|
||||||
|
|
||||||
|
if ek[pos] != hashStartSep {
|
||||||
|
return nil, nil, errSetKey
|
||||||
|
}
|
||||||
|
|
||||||
|
pos++
|
||||||
|
member := ek[pos:]
|
||||||
|
return key, member, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sEncodeStartKey(key []byte) []byte {
|
||||||
|
return db.sEncodeSetKey(key, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sEncodeStopKey(key []byte) []byte {
|
||||||
|
k := db.sEncodeSetKey(key, nil)
|
||||||
|
|
||||||
|
k[len(k)-1] = setStopSep
|
||||||
|
|
||||||
|
return k
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sFlush() (drop int64, err error) {
|
||||||
|
minKey := make([]byte, 2)
|
||||||
|
minKey[0] = db.index
|
||||||
|
minKey[1] = SetType
|
||||||
|
|
||||||
|
maxKey := make([]byte, 2)
|
||||||
|
maxKey[0] = db.index
|
||||||
|
maxKey[1] = SSizeType + 1
|
||||||
|
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
drop, err = db.flushRegion(t, minKey, maxKey)
|
||||||
|
err = db.expFlush(t, SetType)
|
||||||
|
|
||||||
|
err = t.Commit()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sDelete(t *tx, key []byte) int64 {
|
||||||
|
sk := db.sEncodeSizeKey(key)
|
||||||
|
start := db.sEncodeStartKey(key)
|
||||||
|
stop := db.sEncodeStopKey(key)
|
||||||
|
|
||||||
|
var num int64 = 0
|
||||||
|
it := db.db.RangeLimitIterator(start, stop, store.RangeROpen, 0, -1)
|
||||||
|
for ; it.Valid(); it.Next() {
|
||||||
|
t.Delete(it.RawKey())
|
||||||
|
num++
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Close()
|
||||||
|
|
||||||
|
t.Delete(sk)
|
||||||
|
return num
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sIncrSize(key []byte, delta int64) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
sk := db.sEncodeSizeKey(key)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var size int64 = 0
|
||||||
|
if size, err = Int64(db.db.Get(sk)); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
size += delta
|
||||||
|
if size <= 0 {
|
||||||
|
size = 0
|
||||||
|
t.Delete(sk)
|
||||||
|
db.rmExpire(t, SetType, key)
|
||||||
|
} else {
|
||||||
|
t.Put(sk, PutInt64(size))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sExpireAt(key []byte, when int64) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
if scnt, err := db.SCard(key); err != nil || scnt == 0 {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
db.expireAt(t, SetType, key, when)
|
||||||
|
if err := t.Commit(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sSetItem(key []byte, member []byte) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
ek := db.sEncodeSetKey(key, member)
|
||||||
|
|
||||||
|
var n int64 = 1
|
||||||
|
if v, _ := db.db.Get(ek); v != nil {
|
||||||
|
n = 0
|
||||||
|
} else {
|
||||||
|
if _, err := db.sIncrSize(key, 1); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Put(ek, nil)
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SAdd(key []byte, args ...[]byte) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var ek []byte
|
||||||
|
var num int64 = 0
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
if err := checkSetKMSize(key, args[i]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ek = db.sEncodeSetKey(key, args[i])
|
||||||
|
|
||||||
|
if v, err := db.db.Get(ek); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if v == nil {
|
||||||
|
num++
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Put(ek, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = db.sIncrSize(key, num); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Commit()
|
||||||
|
return num, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SCard(key []byte) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sk := db.sEncodeSizeKey(key)
|
||||||
|
|
||||||
|
return Int64(db.db.Get(sk))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sDiffGeneric(keys ...[]byte) ([][]byte, error) {
|
||||||
|
destMap := make(map[string]bool)
|
||||||
|
|
||||||
|
members, err := db.SMembers(keys[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range members {
|
||||||
|
destMap[String(m)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, k := range keys[1:] {
|
||||||
|
members, err := db.SMembers(k)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range members {
|
||||||
|
if _, ok := destMap[String(m)]; !ok {
|
||||||
|
continue
|
||||||
|
} else if ok {
|
||||||
|
delete(destMap, String(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// O - A = O, O is zero set.
|
||||||
|
if len(destMap) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := make([][]byte, len(destMap))
|
||||||
|
idx := 0
|
||||||
|
for k, v := range destMap {
|
||||||
|
if !v {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slice[idx] = []byte(k)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SDiff(keys ...[]byte) ([][]byte, error) {
|
||||||
|
v, err := db.sDiffGeneric(keys...)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SDiffStore(dstKey []byte, keys ...[]byte) (int64, error) {
|
||||||
|
n, err := db.sStoreGeneric(dstKey, DiffType, keys...)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sInterGeneric(keys ...[]byte) ([][]byte, error) {
|
||||||
|
destMap := make(map[string]bool)
|
||||||
|
|
||||||
|
members, err := db.SMembers(keys[0])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range members {
|
||||||
|
destMap[String(m)] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, key := range keys[1:] {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
members, err := db.SMembers(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if len(members) == 0 {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
tempMap := make(map[string]bool)
|
||||||
|
for _, member := range members {
|
||||||
|
if err := checkKeySize(member); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, ok := destMap[String(member)]; ok {
|
||||||
|
tempMap[String(member)] = true //mark this item as selected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
destMap = tempMap //reduce the size of the result set
|
||||||
|
if len(destMap) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := make([][]byte, len(destMap))
|
||||||
|
idx := 0
|
||||||
|
for k, v := range destMap {
|
||||||
|
if !v {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
slice[idx] = []byte(k)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SInter(keys ...[]byte) ([][]byte, error) {
|
||||||
|
v, err := db.sInterGeneric(keys...)
|
||||||
|
return v, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SInterStore(dstKey []byte, keys ...[]byte) (int64, error) {
|
||||||
|
n, err := db.sStoreGeneric(dstKey, InterType, keys...)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SIsMember(key []byte, member []byte) (int64, error) {
|
||||||
|
ek := db.sEncodeSetKey(key, member)
|
||||||
|
|
||||||
|
var n int64 = 1
|
||||||
|
if v, err := db.db.Get(ek); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if v == nil {
|
||||||
|
n = 0
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SMembers(key []byte) ([][]byte, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
start := db.sEncodeStartKey(key)
|
||||||
|
stop := db.sEncodeStopKey(key)
|
||||||
|
|
||||||
|
v := make([][]byte, 0, 16)
|
||||||
|
|
||||||
|
it := db.db.RangeLimitIterator(start, stop, store.RangeROpen, 0, -1)
|
||||||
|
for ; it.Valid(); it.Next() {
|
||||||
|
_, m, err := db.sDecodeSetKey(it.Key())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
v = append(v, m)
|
||||||
|
}
|
||||||
|
|
||||||
|
it.Close()
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SRem(key []byte, args ...[]byte) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
var ek []byte
|
||||||
|
var v []byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
it := db.db.NewIterator()
|
||||||
|
defer it.Close()
|
||||||
|
|
||||||
|
var num int64 = 0
|
||||||
|
for i := 0; i < len(args); i++ {
|
||||||
|
if err := checkSetKMSize(key, args[i]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ek = db.sEncodeSetKey(key, args[i])
|
||||||
|
|
||||||
|
v = it.RawFind(ek)
|
||||||
|
if v == nil {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
num++
|
||||||
|
t.Delete(ek)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = db.sIncrSize(key, -num); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Commit()
|
||||||
|
return num, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sUnionGeneric(keys ...[]byte) ([][]byte, error) {
|
||||||
|
dstMap := make(map[string]bool)
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
members, err := db.SMembers(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, member := range members {
|
||||||
|
dstMap[String(member)] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
slice := make([][]byte, len(dstMap))
|
||||||
|
idx := 0
|
||||||
|
for k, v := range dstMap {
|
||||||
|
if !v {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
slice[idx] = []byte(k)
|
||||||
|
idx++
|
||||||
|
}
|
||||||
|
|
||||||
|
return slice, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SUnion(keys ...[]byte) ([][]byte, error) {
|
||||||
|
v, err := db.sUnionGeneric(keys...)
|
||||||
|
return v, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SUnionStore(dstKey []byte, keys ...[]byte) (int64, error) {
|
||||||
|
n, err := db.sStoreGeneric(dstKey, UnionType, keys...)
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) sStoreGeneric(dstKey []byte, optType byte, keys ...[]byte) (int64, error) {
|
||||||
|
if err := checkKeySize(dstKey); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
db.sDelete(t, dstKey)
|
||||||
|
|
||||||
|
var err error
|
||||||
|
var ek []byte
|
||||||
|
var num int64 = 0
|
||||||
|
var v [][]byte
|
||||||
|
|
||||||
|
switch optType {
|
||||||
|
case UnionType:
|
||||||
|
v, err = db.sUnionGeneric(keys...)
|
||||||
|
case DiffType:
|
||||||
|
v, err = db.sDiffGeneric(keys...)
|
||||||
|
case InterType:
|
||||||
|
v, err = db.sInterGeneric(keys...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, m := range v {
|
||||||
|
if err := checkSetKMSize(dstKey, m); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ek = db.sEncodeSetKey(dstKey, m)
|
||||||
|
|
||||||
|
if v, err := db.db.Get(ek); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if v == nil {
|
||||||
|
num++
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Put(ek, nil)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = db.sIncrSize(dstKey, num); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = t.Commit()
|
||||||
|
return num, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SClear(key []byte) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
num := db.sDelete(t, key)
|
||||||
|
db.rmExpire(t, SetType, key)
|
||||||
|
|
||||||
|
err := t.Commit()
|
||||||
|
return num, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SMclear(keys ...[]byte) (int64, error) {
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
for _, key := range keys {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
db.sDelete(t, key)
|
||||||
|
db.rmExpire(t, SetType, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
err := t.Commit()
|
||||||
|
return int64(len(keys)), err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SExpire(key []byte, duration int64) (int64, error) {
|
||||||
|
if duration <= 0 {
|
||||||
|
return 0, errExpireValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.sExpireAt(key, time.Now().Unix()+duration)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SExpireAt(key []byte, when int64) (int64, error) {
|
||||||
|
if when <= time.Now().Unix() {
|
||||||
|
return 0, errExpireValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.sExpireAt(key, when)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) STTL(key []byte) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return -1, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.ttl(SetType, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SPersist(key []byte) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
t := db.setTx
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
n, err := db.rmExpire(t, SetType, key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
err = t.Commit()
|
||||||
|
return n, err
|
||||||
|
}
|
|
@ -0,0 +1,339 @@
|
||||||
|
package ledis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSetCodec(t *testing.T) {
|
||||||
|
db := getTestDB()
|
||||||
|
|
||||||
|
key := []byte("key")
|
||||||
|
member := []byte("member")
|
||||||
|
|
||||||
|
ek := db.sEncodeSizeKey(key)
|
||||||
|
if k, err := db.sDecodeSizeKey(ek); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(k) != "key" {
|
||||||
|
t.Fatal(string(k))
|
||||||
|
}
|
||||||
|
|
||||||
|
ek = db.sEncodeSetKey(key, member)
|
||||||
|
if k, m, err := db.sDecodeSetKey(ek); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(k) != "key" {
|
||||||
|
t.Fatal(string(k))
|
||||||
|
} else if string(m) != "member" {
|
||||||
|
t.Fatal(string(m))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDBSet(t *testing.T) {
|
||||||
|
db := getTestDB()
|
||||||
|
|
||||||
|
key := []byte("testdb_set_a")
|
||||||
|
member := []byte("member")
|
||||||
|
key1 := []byte("testdb_set_a1")
|
||||||
|
key2 := []byte("testdb_set_a2")
|
||||||
|
member1 := []byte("testdb_set_m1")
|
||||||
|
member2 := []byte("testdb_set_m2")
|
||||||
|
|
||||||
|
// if n, err := db.sSetItem(key, []byte("m1")); err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
|
// } else if n != 1 {
|
||||||
|
// t.Fatal(n)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if size, err := db.sIncrSize(key, 1); err != nil {
|
||||||
|
// t.Fatal(err)
|
||||||
|
// } else if size != 1 {
|
||||||
|
// t.Fatal(size)
|
||||||
|
// }
|
||||||
|
|
||||||
|
if n, err := db.SAdd(key, member); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cnt, err := db.SCard(key); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if cnt != 1 {
|
||||||
|
t.Fatal(cnt)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SIsMember(key, member); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SMembers(key); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v[0]) != "member" {
|
||||||
|
t.Fatal(string(v[0]))
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SRem(key, member); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SAdd(key1, member1, member2)
|
||||||
|
|
||||||
|
if n, err := db.SClear(key1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SAdd(key1, member1, member2)
|
||||||
|
db.SAdd(key2, member1, member2, []byte("xxx"))
|
||||||
|
|
||||||
|
if n, _ := db.SCard(key2); n != 3 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
if n, err := db.SMclear(key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
db.SAdd(key2, member1, member2)
|
||||||
|
if n, err := db.SExpire(key2, 3600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SExpireAt(key2, time.Now().Unix()+3600); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.STTL(key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n < 0 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SPersist(key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetOperation(t *testing.T) {
|
||||||
|
db := getTestDB()
|
||||||
|
testUnion(db, t)
|
||||||
|
testInter(db, t)
|
||||||
|
testDiff(db, t)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func testUnion(db *DB, t *testing.T) {
|
||||||
|
|
||||||
|
key := []byte("testdb_set_union_1")
|
||||||
|
key1 := []byte("testdb_set_union_2")
|
||||||
|
key2 := []byte("testdb_set_union_2")
|
||||||
|
// member1 := []byte("testdb_set_m1")
|
||||||
|
// member2 := []byte("testdb_set_m2")
|
||||||
|
|
||||||
|
m1 := []byte("m1")
|
||||||
|
m2 := []byte("m2")
|
||||||
|
m3 := []byte("m3")
|
||||||
|
db.SAdd(key, m1, m2)
|
||||||
|
db.SAdd(key1, m1, m3)
|
||||||
|
db.SAdd(key2, m2, m3)
|
||||||
|
if _, err := db.sUnionGeneric(key, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := db.SUnion(key, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstkey := []byte("union_dsk")
|
||||||
|
if num, err := db.SUnionStore(dstkey, key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if num != 3 {
|
||||||
|
t.Fatal(num)
|
||||||
|
}
|
||||||
|
if _, err := db.SMembers(dstkey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SCard(dstkey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 3 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, _ := db.SUnion(key1, key2)
|
||||||
|
v2, _ := db.SUnion(key2, key1)
|
||||||
|
if len(v1) != len(v2) {
|
||||||
|
t.Fatal(v1, v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, _ = db.SUnion(key, key1, key2)
|
||||||
|
v2, _ = db.SUnion(key, key2, key1)
|
||||||
|
if len(v1) != len(v2) {
|
||||||
|
t.Fatal(v1, v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SUnion(key, key); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 2 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
empKey := []byte("0")
|
||||||
|
if v, err := db.SUnion(key, empKey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 2 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testInter(db *DB, t *testing.T) {
|
||||||
|
key1 := []byte("testdb_set_inter_1")
|
||||||
|
key2 := []byte("testdb_set_inter_2")
|
||||||
|
key3 := []byte("testdb_set_inter_3")
|
||||||
|
|
||||||
|
m1 := []byte("m1")
|
||||||
|
m2 := []byte("m2")
|
||||||
|
m3 := []byte("m3")
|
||||||
|
m4 := []byte("m4")
|
||||||
|
|
||||||
|
db.SAdd(key1, m1, m2)
|
||||||
|
db.SAdd(key2, m2, m3, m4)
|
||||||
|
db.SAdd(key3, m2, m4)
|
||||||
|
|
||||||
|
if v, err := db.sInterGeneric(key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 1 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SInter(key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 1 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstKey := []byte("inter_dsk")
|
||||||
|
if n, err := db.SInterStore(dstKey, key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
k1 := []byte("set_k1")
|
||||||
|
k2 := []byte("set_k2")
|
||||||
|
|
||||||
|
db.SAdd(k1, m1, m3, m4)
|
||||||
|
db.SAdd(k2, m2, m3)
|
||||||
|
if n, err := db.SInterStore([]byte("set_xxx"), k1, k2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, _ := db.SInter(key1, key2)
|
||||||
|
v2, _ := db.SInter(key2, key1)
|
||||||
|
if len(v1) != len(v2) {
|
||||||
|
t.Fatal(v1, v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
v1, _ = db.SInter(key1, key2, key3)
|
||||||
|
v2, _ = db.SInter(key2, key3, key1)
|
||||||
|
if len(v1) != len(v2) {
|
||||||
|
t.Fatal(v1, v2)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SInter(key1, key1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 2 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
empKey := []byte("0")
|
||||||
|
if v, err := db.SInter(key1, empKey); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 0 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SInter(empKey, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 0 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testDiff(db *DB, t *testing.T) {
|
||||||
|
key0 := []byte("testdb_set_diff_0")
|
||||||
|
key1 := []byte("testdb_set_diff_1")
|
||||||
|
key2 := []byte("testdb_set_diff_2")
|
||||||
|
key3 := []byte("testdb_set_diff_3")
|
||||||
|
|
||||||
|
m1 := []byte("m1")
|
||||||
|
m2 := []byte("m2")
|
||||||
|
m3 := []byte("m3")
|
||||||
|
m4 := []byte("m4")
|
||||||
|
|
||||||
|
db.SAdd(key1, m1, m2)
|
||||||
|
db.SAdd(key2, m2, m3, m4)
|
||||||
|
db.SAdd(key3, m3)
|
||||||
|
|
||||||
|
if _, err := db.sDiffGeneric(key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 1 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
dstKey := []byte("diff_dsk")
|
||||||
|
if n, err := db.SDiffStore(dstKey, key1, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key2, key1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 2 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key1, key2, key3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 1 {
|
||||||
|
t.Fatal(v) //return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key2, key2); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 0 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key0, key1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 0 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.SDiff(key1, key0); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if len(v) != 2 {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
}
|
|
@ -344,22 +344,6 @@ func TestBitErrorParams(t *testing.T) {
|
||||||
t.Fatal("invalid err of %v", err)
|
t.Fatal("invalid err of %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := c.Do("bexpire", "test_bexpire"); err == nil {
|
|
||||||
t.Fatal("invalid err of %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.Do("bexpireat", "test_bexpireat"); err == nil {
|
|
||||||
t.Fatal("invalid err of %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.Do("bttl"); err == nil {
|
|
||||||
t.Fatal("invalid err of %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := c.Do("bpersist"); err == nil {
|
|
||||||
t.Fatal("invalid err of %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
//bexpire
|
//bexpire
|
||||||
if _, err := c.Do("bexpire", "test_bexpire"); err == nil {
|
if _, err := c.Do("bexpire", "test_bexpire"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
t.Fatal("invalid err of %v", err)
|
||||||
|
|
|
@ -0,0 +1,283 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
|
)
|
||||||
|
|
||||||
|
func saddCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) < 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SAdd(args[0], args[1:]...); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func soptGeneric(req *requestContext, optType byte) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) < 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
var v [][]byte
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch optType {
|
||||||
|
case ledis.UnionType:
|
||||||
|
v, err = req.db.SUnion(args...)
|
||||||
|
case ledis.DiffType:
|
||||||
|
v, err = req.db.SDiff(args...)
|
||||||
|
case ledis.InterType:
|
||||||
|
v, err = req.db.SInter(args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeSliceArray(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func soptStoreGeneric(req *requestContext, optType byte) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) < 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
var n int64
|
||||||
|
var err error
|
||||||
|
|
||||||
|
switch optType {
|
||||||
|
case ledis.UnionType:
|
||||||
|
n, err = req.db.SUnionStore(args[0], args[1:]...)
|
||||||
|
case ledis.DiffType:
|
||||||
|
n, err = req.db.SDiffStore(args[0], args[1:]...)
|
||||||
|
case ledis.InterType:
|
||||||
|
n, err = req.db.SInterStore(args[0], args[1:]...)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scardCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SCard(args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sdiffCommand(req *requestContext) error {
|
||||||
|
return soptGeneric(req, ledis.DiffType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sdiffstoreCommand(req *requestContext) error {
|
||||||
|
return soptStoreGeneric(req, ledis.DiffType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinterCommand(req *requestContext) error {
|
||||||
|
return soptGeneric(req, ledis.InterType)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func sinterstoreCommand(req *requestContext) error {
|
||||||
|
return soptStoreGeneric(req, ledis.InterType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sismemberCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SIsMember(args[0], args[1]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func smembersCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := req.db.SMembers(args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeSliceArray(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func sremCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) < 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SRem(args[0], args[1:]...); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func sunionCommand(req *requestContext) error {
|
||||||
|
return soptGeneric(req, ledis.UnionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sunionstoreCommand(req *requestContext) error {
|
||||||
|
return soptStoreGeneric(req, ledis.UnionType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func sclearCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SClear(args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func smclearCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) < 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SMclear(args...); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sexpireCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
duration, err := ledis.StrInt64(args[1], nil)
|
||||||
|
if err != nil {
|
||||||
|
return ErrValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := req.db.SExpire(args[0], duration); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sexpireAtCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
when, err := ledis.StrInt64(args[1], nil)
|
||||||
|
if err != nil {
|
||||||
|
return ErrValue
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := req.db.SExpireAt(args[0], when); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func sttlCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := req.db.STTL(args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func spersistCommand(req *requestContext) error {
|
||||||
|
args := req.args
|
||||||
|
if len(args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := req.db.SPersist(args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
req.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("sadd", saddCommand)
|
||||||
|
register("scard", scardCommand)
|
||||||
|
register("sdiff", sdiffCommand)
|
||||||
|
register("sdiffstore", sdiffstoreCommand)
|
||||||
|
register("sinter", sinterCommand)
|
||||||
|
register("sinterstore", sinterstoreCommand)
|
||||||
|
register("sismember", sismemberCommand)
|
||||||
|
register("smembers", smembersCommand)
|
||||||
|
register("srem", sremCommand)
|
||||||
|
register("sunion", sunionCommand)
|
||||||
|
register("sunionstore", sunionstoreCommand)
|
||||||
|
register("sclear", sclearCommand)
|
||||||
|
register("smclear", smclearCommand)
|
||||||
|
register("sexpire", sexpireCommand)
|
||||||
|
register("sexpireat", sexpireAtCommand)
|
||||||
|
register("sttl", sttlCommand)
|
||||||
|
register("spersist", spersistCommand)
|
||||||
|
}
|
|
@ -0,0 +1,203 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/siddontang/ledisdb/client/go/ledis"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSet(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
key1 := "testdb_cmd_set_1"
|
||||||
|
key2 := "testdb_cmd_set_2"
|
||||||
|
|
||||||
|
if n, err := ledis.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("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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 4 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.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 {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 4 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Do("sadd", key1, 0)
|
||||||
|
c.Do("sadd", key2, 1)
|
||||||
|
if n, err := ledis.Int(c.Do("smclear", key1, key2)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 2 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetErrorParams(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
if _, err := c.Do("sadd", "test_sadd"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("scard"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("scard", "k1", "k2"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sdiff"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sdiffstore", "dstkey"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sinter"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sinterstore", "dstkey"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sunion"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sunionstore", "dstkey"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sismember", "k1"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sismember", "k1", "m1", "m2"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("smembers"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("smembers", "k1", "k2"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("srem"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("srem", "key"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sclear"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sclear", "k1", "k2"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("smclear"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sexpire", "set_expire"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sexpire", "set_expire", "aaa"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sexpireat", "set_expireat"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sexpireat", "set_expireat", "aaa"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("sttl"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := c.Do("spersist"); err == nil {
|
||||||
|
t.Fatal("invalid err of %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -79,3 +79,353 @@ func TestKVExpire(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSetExpire(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
k := "set_ttl"
|
||||||
|
c.Do("sadd", k, "123")
|
||||||
|
|
||||||
|
// expire + ttl
|
||||||
|
exp := int64(10)
|
||||||
|
if n, err := ledis.Int(c.Do("sexpire", k, exp)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("sttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != exp {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expireat + ttl
|
||||||
|
tm := now() + 3
|
||||||
|
if n, err := ledis.Int(c.Do("sexpireat", k, tm)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("sttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != 3 {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
kErr := "not_exist_ttl"
|
||||||
|
|
||||||
|
// err - expire, expireat
|
||||||
|
if n, err := ledis.Int(c.Do("sexpire", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("sexpireat", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("sttl", kErr)); err != nil || n != -1 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("spersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("sexpire", k, 10)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("spersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListExpire(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
k := "list_ttl"
|
||||||
|
c.Do("rpush", k, "123")
|
||||||
|
|
||||||
|
// expire + ttl
|
||||||
|
exp := int64(10)
|
||||||
|
if n, err := ledis.Int(c.Do("lexpire", k, exp)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("lttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != exp {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expireat + ttl
|
||||||
|
tm := now() + 3
|
||||||
|
if n, err := ledis.Int(c.Do("lexpireat", k, tm)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("lttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != 3 {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
kErr := "not_exist_ttl"
|
||||||
|
|
||||||
|
// err - expire, expireat
|
||||||
|
if n, err := ledis.Int(c.Do("lexpire", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("lexpireat", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("lttl", kErr)); err != nil || n != -1 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("lpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("lexpire", k, 10)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("lpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHashExpire(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
k := "hash_ttl"
|
||||||
|
c.Do("hset", k, "f", 123)
|
||||||
|
|
||||||
|
// expire + ttl
|
||||||
|
exp := int64(10)
|
||||||
|
if n, err := ledis.Int(c.Do("hexpire", k, exp)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("httl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != exp {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expireat + ttl
|
||||||
|
tm := now() + 3
|
||||||
|
if n, err := ledis.Int(c.Do("hexpireat", k, tm)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("httl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != 3 {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
kErr := "not_exist_ttl"
|
||||||
|
|
||||||
|
// err - expire, expireat
|
||||||
|
if n, err := ledis.Int(c.Do("hexpire", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("hexpireat", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("httl", kErr)); err != nil || n != -1 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("hpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("hexpire", k, 10)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("hpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestZsetExpire(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
k := "zset_ttl"
|
||||||
|
c.Do("zadd", k, 123, "m")
|
||||||
|
|
||||||
|
// expire + ttl
|
||||||
|
exp := int64(10)
|
||||||
|
if n, err := ledis.Int(c.Do("zexpire", k, exp)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("zttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != exp {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expireat + ttl
|
||||||
|
tm := now() + 3
|
||||||
|
if n, err := ledis.Int(c.Do("zexpireat", k, tm)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("zttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != 3 {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
kErr := "not_exist_ttl"
|
||||||
|
|
||||||
|
// err - expire, expireat
|
||||||
|
if n, err := ledis.Int(c.Do("zexpire", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("zexpireat", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("zttl", kErr)); err != nil || n != -1 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("zpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("zexpire", k, 10)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("zpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBitmapExpire(t *testing.T) {
|
||||||
|
c := getTestConn()
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
k := "bit_ttl"
|
||||||
|
c.Do("bsetbit", k, 0, 1)
|
||||||
|
|
||||||
|
// expire + ttl
|
||||||
|
exp := int64(10)
|
||||||
|
if n, err := ledis.Int(c.Do("bexpire", k, exp)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("bttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != exp {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// expireat + ttl
|
||||||
|
tm := now() + 3
|
||||||
|
if n, err := ledis.Int(c.Do("bexpireat", k, tm)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ttl, err := ledis.Int64(c.Do("bttl", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if ttl != 3 {
|
||||||
|
t.Fatal(ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
kErr := "not_exist_ttl"
|
||||||
|
|
||||||
|
// err - expire, expireat
|
||||||
|
if n, err := ledis.Int(c.Do("bexpire", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bexpireat", kErr, tm)); err != nil || n != 0 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bttl", kErr)); err != nil || n != -1 {
|
||||||
|
t.Fatal(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bexpire", k, 10)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bpersist", k)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue