forked from mirror/ledisdb
refactor scan
This commit is contained in:
parent
218700ce44
commit
f34d3ac27b
|
@ -6,6 +6,43 @@ import (
|
||||||
|
|
||||||
const Version = "0.4"
|
const Version = "0.4"
|
||||||
|
|
||||||
|
type DataType byte
|
||||||
|
|
||||||
|
// for out use
|
||||||
|
const (
|
||||||
|
KV DataType = iota
|
||||||
|
LIST
|
||||||
|
HASH
|
||||||
|
SET
|
||||||
|
ZSET
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DataType) String() string {
|
||||||
|
switch d {
|
||||||
|
case KV:
|
||||||
|
return KVName
|
||||||
|
case LIST:
|
||||||
|
return ListName
|
||||||
|
case HASH:
|
||||||
|
return HashName
|
||||||
|
case SET:
|
||||||
|
return SetName
|
||||||
|
case ZSET:
|
||||||
|
return ZSetName
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
KVName = "KV"
|
||||||
|
ListName = "LIST"
|
||||||
|
HashName = "HASH"
|
||||||
|
SetName = "SET"
|
||||||
|
ZSetName = "ZSET"
|
||||||
|
)
|
||||||
|
|
||||||
|
// for backend store
|
||||||
const (
|
const (
|
||||||
NoneType byte = 0
|
NoneType byte = 0
|
||||||
KVType byte = 1
|
KVType byte = 1
|
||||||
|
|
|
@ -128,7 +128,7 @@ func (db *DB) flushType(t *batch, dataType byte) (drop int64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var keys [][]byte
|
var keys [][]byte
|
||||||
keys, err = db.scan(metaDataType, nil, 1024, false, "")
|
keys, err = db.scanGeneric(metaDataType, nil, 1024, false, "", false)
|
||||||
for len(keys) != 0 || err != nil {
|
for len(keys) != 0 || err != nil {
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
deleteFunc(t, key)
|
deleteFunc(t, key)
|
||||||
|
@ -141,7 +141,7 @@ func (db *DB) flushType(t *batch, dataType byte) (drop int64, err error) {
|
||||||
} else {
|
} else {
|
||||||
drop += int64(len(keys))
|
drop += int64(len(keys))
|
||||||
}
|
}
|
||||||
keys, err = db.scan(metaDataType, nil, 1024, false, "")
|
keys, err = db.scanGeneric(metaDataType, nil, 1024, false, "", false)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,46 @@ import (
|
||||||
var errDataType = errors.New("error data type")
|
var errDataType = errors.New("error data type")
|
||||||
var errMetaKey = errors.New("error meta key")
|
var errMetaKey = errors.New("error meta key")
|
||||||
|
|
||||||
func (db *DB) scan(dataType byte, key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
//fif inclusive is true, scan range [cursor, inf) else (cursor, inf)
|
||||||
return db.scanGeneric(dataType, key, count, inclusive, match, false)
|
func (db *DB) Scan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
||||||
|
storeDataType, err := getDataStoreType(dataType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.scanGeneric(storeDataType, cursor, count, inclusive, match, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) revscan(dataType byte, key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
//if inclusive is true, revscan range (-inf, cursor] else (inf, cursor)
|
||||||
return db.scanGeneric(dataType, key, count, inclusive, match, true)
|
func (db *DB) RevScan(dataType DataType, cursor []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
||||||
|
storeDataType, err := getDataStoreType(dataType)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return db.scanGeneric(storeDataType, cursor, count, inclusive, match, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) scanGeneric(dataType byte, key []byte, count int,
|
func getDataStoreType(dataType DataType) (byte, error) {
|
||||||
|
var storeDataType byte
|
||||||
|
switch dataType {
|
||||||
|
case KV:
|
||||||
|
storeDataType = KVType
|
||||||
|
case LIST:
|
||||||
|
storeDataType = LMetaType
|
||||||
|
case HASH:
|
||||||
|
storeDataType = HSizeType
|
||||||
|
case SET:
|
||||||
|
storeDataType = SSizeType
|
||||||
|
case ZSET:
|
||||||
|
storeDataType = ZSizeType
|
||||||
|
default:
|
||||||
|
return 0, errDataType
|
||||||
|
}
|
||||||
|
return storeDataType, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) scanGeneric(storeDataType byte, key []byte, count int,
|
||||||
inclusive bool, match string, reverse bool) ([][]byte, error) {
|
inclusive bool, match string, reverse bool) ([][]byte, error) {
|
||||||
var minKey, maxKey []byte
|
var minKey, maxKey []byte
|
||||||
var err error
|
var err error
|
||||||
|
@ -32,10 +63,10 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int,
|
||||||
tp := store.RangeOpen
|
tp := store.RangeOpen
|
||||||
|
|
||||||
if !reverse {
|
if !reverse {
|
||||||
if minKey, err = db.encodeScanMinKey(dataType, key); err != nil {
|
if minKey, err = db.encodeScanMinKey(storeDataType, key); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if maxKey, err = db.encodeScanMaxKey(dataType, nil); err != nil {
|
if maxKey, err = db.encodeScanMaxKey(storeDataType, nil); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,10 +74,10 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int,
|
||||||
tp = store.RangeROpen
|
tp = store.RangeROpen
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if minKey, err = db.encodeScanMinKey(dataType, nil); err != nil {
|
if minKey, err = db.encodeScanMinKey(storeDataType, nil); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if maxKey, err = db.encodeScanMaxKey(dataType, key); err != nil {
|
if maxKey, err = db.encodeScanMaxKey(storeDataType, key); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +100,7 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int,
|
||||||
v := make([][]byte, 0, count)
|
v := make([][]byte, 0, count)
|
||||||
|
|
||||||
for i := 0; it.Valid() && i < count; it.Next() {
|
for i := 0; it.Valid() && i < count; it.Next() {
|
||||||
if k, err := db.decodeScanKey(dataType, it.Key()); err != nil {
|
if k, err := db.decodeScanKey(storeDataType, it.Key()); err != nil {
|
||||||
continue
|
continue
|
||||||
} else if r != nil && !r.Match(k) {
|
} else if r != nil && !r.Match(k) {
|
||||||
continue
|
continue
|
||||||
|
@ -82,36 +113,36 @@ func (db *DB) scanGeneric(dataType byte, key []byte, count int,
|
||||||
return v, nil
|
return v, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) encodeScanMinKey(dataType byte, key []byte) ([]byte, error) {
|
func (db *DB) encodeScanMinKey(storeDataType byte, key []byte) ([]byte, error) {
|
||||||
if len(key) == 0 {
|
if len(key) == 0 {
|
||||||
return db.encodeScanKey(dataType, nil)
|
return db.encodeScanKey(storeDataType, nil)
|
||||||
} else {
|
} else {
|
||||||
if err := checkKeySize(key); err != nil {
|
if err := checkKeySize(key); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return db.encodeScanKey(dataType, key)
|
return db.encodeScanKey(storeDataType, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) encodeScanMaxKey(dataType byte, key []byte) ([]byte, error) {
|
func (db *DB) encodeScanMaxKey(storeDataType byte, key []byte) ([]byte, error) {
|
||||||
if len(key) > 0 {
|
if len(key) > 0 {
|
||||||
if err := checkKeySize(key); err != nil {
|
if err := checkKeySize(key); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return db.encodeScanKey(dataType, key)
|
return db.encodeScanKey(storeDataType, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
k, err := db.encodeScanKey(dataType, nil)
|
k, err := db.encodeScanKey(storeDataType, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
k[len(k)-1] = dataType + 1
|
k[len(k)-1] = storeDataType + 1
|
||||||
return k, nil
|
return k, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) encodeScanKey(dataType byte, key []byte) ([]byte, error) {
|
func (db *DB) encodeScanKey(storeDataType byte, key []byte) ([]byte, error) {
|
||||||
switch dataType {
|
switch storeDataType {
|
||||||
case KVType:
|
case KVType:
|
||||||
return db.encodeKVKey(key), nil
|
return db.encodeKVKey(key), nil
|
||||||
case LMetaType:
|
case LMetaType:
|
||||||
|
@ -128,8 +159,8 @@ func (db *DB) encodeScanKey(dataType byte, key []byte) ([]byte, error) {
|
||||||
return nil, errDataType
|
return nil, errDataType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func (db *DB) decodeScanKey(dataType byte, ek []byte) ([]byte, error) {
|
func (db *DB) decodeScanKey(storeDataType byte, ek []byte) ([]byte, error) {
|
||||||
if len(ek) < 2 || ek[0] != db.index || ek[1] != dataType {
|
if len(ek) < 2 || ek[0] != db.index || ek[1] != storeDataType {
|
||||||
return nil, errMetaKey
|
return nil, errMetaKey
|
||||||
}
|
}
|
||||||
return ek[2:], nil
|
return ek[2:], nil
|
||||||
|
|
|
@ -21,13 +21,13 @@ func TestDBScan(t *testing.T) {
|
||||||
|
|
||||||
db.FlushAll()
|
db.FlushAll()
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 10, true, ""); err != nil {
|
if v, err := db.Scan(KV, nil, 10, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal(len(v))
|
t.Fatal(len(v))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 10, true, ""); err != nil {
|
if v, err := db.RevScan(KV, nil, 10, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal(len(v))
|
t.Fatal(len(v))
|
||||||
|
@ -37,73 +37,73 @@ func TestDBScan(t *testing.T) {
|
||||||
db.Set([]byte("b"), []byte{})
|
db.Set([]byte("b"), []byte{})
|
||||||
db.Set([]byte("c"), []byte{})
|
db.Set([]byte("c"), []byte{})
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 1, true, ""); err != nil {
|
if v, err := db.Scan(KV, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "a")
|
checkTestScan(t, v, "a")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan([]byte("a"), 2, false, ""); err != nil {
|
if v, err := db.Scan(KV, []byte("a"), 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "b", "c")
|
checkTestScan(t, v, "b", "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3, true, ""); err != nil {
|
if v, err := db.Scan(KV, nil, 3, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "a", "b", "c")
|
checkTestScan(t, v, "a", "b", "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3, true, "b"); err != nil {
|
if v, err := db.Scan(KV, nil, 3, true, "b"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "b")
|
checkTestScan(t, v, "b")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3, true, "."); err != nil {
|
if v, err := db.Scan(KV, nil, 3, true, "."); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "a", "b", "c")
|
checkTestScan(t, v, "a", "b", "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3, true, "a+"); err != nil {
|
if v, err := db.Scan(KV, nil, 3, true, "a+"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "a")
|
checkTestScan(t, v, "a")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 1, true, ""); err != nil {
|
if v, err := db.RevScan(KV, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "c")
|
checkTestScan(t, v, "c")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan([]byte("c"), 2, false, ""); err != nil {
|
if v, err := db.RevScan(KV, []byte("c"), 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "b", "a")
|
checkTestScan(t, v, "b", "a")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 3, true, ""); err != nil {
|
if v, err := db.RevScan(KV, nil, 3, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "c", "b", "a")
|
checkTestScan(t, v, "c", "b", "a")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 3, true, "b"); err != nil {
|
if v, err := db.RevScan(KV, nil, 3, true, "b"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "b")
|
checkTestScan(t, v, "b")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 3, true, "."); err != nil {
|
if v, err := db.RevScan(KV, nil, 3, true, "."); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "c", "b", "a")
|
checkTestScan(t, v, "c", "b", "a")
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.RevScan(nil, 3, true, "c+"); err != nil {
|
if v, err := db.RevScan(KV, nil, 3, true, "c+"); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else {
|
} else {
|
||||||
checkTestScan(t, v, "c")
|
checkTestScan(t, v, "c")
|
||||||
|
@ -125,7 +125,7 @@ func TestDBHScan(t *testing.T) {
|
||||||
k3 := []byte("k3")
|
k3 := []byte("k3")
|
||||||
db.HSet(k3, []byte("3"), []byte{})
|
db.HSet(k3, []byte("3"), []byte{})
|
||||||
|
|
||||||
if v, err := db.HScan(nil, 1, true, ""); err != nil {
|
if v, err := db.Scan(HASH, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 1 {
|
} else if len(v) != 1 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -133,7 +133,7 @@ func TestDBHScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
t.Fatal("invalid value ", string(v[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.HScan(k1, 2, true, ""); err != nil {
|
if v, err := db.Scan(HASH, k1, 2, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -143,7 +143,7 @@ func TestDBHScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.HScan(k1, 2, false, ""); err != nil {
|
if v, err := db.Scan(HASH, k1, 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -169,7 +169,7 @@ func TestDBZScan(t *testing.T) {
|
||||||
k3 := []byte("k3")
|
k3 := []byte("k3")
|
||||||
db.ZAdd(k3, ScorePair{3, []byte("m")})
|
db.ZAdd(k3, ScorePair{3, []byte("m")})
|
||||||
|
|
||||||
if v, err := db.ZScan(nil, 1, true, ""); err != nil {
|
if v, err := db.Scan(ZSET, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 1 {
|
} else if len(v) != 1 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -177,7 +177,7 @@ func TestDBZScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
t.Fatal("invalid value ", string(v[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.ZScan(k1, 2, true, ""); err != nil {
|
if v, err := db.Scan(ZSET, k1, 2, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -187,7 +187,7 @@ func TestDBZScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.ZScan(k1, 2, false, ""); err != nil {
|
if v, err := db.Scan(ZSET, k1, 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -219,7 +219,7 @@ func TestDBLScan(t *testing.T) {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.LScan(nil, 1, true, ""); err != nil {
|
if v, err := db.Scan(LIST, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 1 {
|
} else if len(v) != 1 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -227,7 +227,7 @@ func TestDBLScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
t.Fatal("invalid value ", string(v[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.LScan(k1, 2, true, ""); err != nil {
|
if v, err := db.Scan(LIST, k1, 2, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -237,7 +237,7 @@ func TestDBLScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.LScan(k1, 2, false, ""); err != nil {
|
if v, err := db.Scan(LIST, k1, 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -249,56 +249,6 @@ func TestDBLScan(t *testing.T) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBBScan(t *testing.T) {
|
|
||||||
// db := getTestDB()
|
|
||||||
|
|
||||||
// db.bFlush()
|
|
||||||
|
|
||||||
// k1 := []byte("k1")
|
|
||||||
// if _, err := db.BSetBit(k1, 1, 1); err != nil {
|
|
||||||
// t.Fatal(err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// k2 := []byte("k2")
|
|
||||||
// if _, err := db.BSetBit(k2, 1, 1); err != nil {
|
|
||||||
// t.Fatal(err.Error())
|
|
||||||
// }
|
|
||||||
// k3 := []byte("k3")
|
|
||||||
|
|
||||||
// if _, err := db.BSetBit(k3, 1, 0); err != nil {
|
|
||||||
// t.Fatal(err.Error())
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if v, err := db.BScan(nil, 1, true, ""); err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// } else if len(v) != 1 {
|
|
||||||
// t.Fatal("invalid length ", len(v))
|
|
||||||
// } else if string(v[0]) != "k1" {
|
|
||||||
// t.Fatal("invalid value ", string(v[0]))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if v, err := db.BScan(k1, 2, true, ""); err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// } else if len(v) != 2 {
|
|
||||||
// t.Fatal("invalid length ", len(v))
|
|
||||||
// } else if string(v[0]) != "k1" {
|
|
||||||
// t.Fatal("invalid value ", string(v[0]))
|
|
||||||
// } else if string(v[1]) != "k2" {
|
|
||||||
// t.Fatal("invalid value ", string(v[1]))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if v, err := db.BScan(k1, 2, false, ""); err != nil {
|
|
||||||
// t.Fatal(err)
|
|
||||||
// } else if len(v) != 2 {
|
|
||||||
// t.Fatal("invalid length ", len(v))
|
|
||||||
// } else if string(v[0]) != "k2" {
|
|
||||||
// t.Fatal("invalid value ", string(v[0]))
|
|
||||||
// } else if string(v[1]) != "k3" {
|
|
||||||
// t.Fatal("invalid value ", string(v[1]))
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDBSScan(t *testing.T) {
|
func TestDBSScan(t *testing.T) {
|
||||||
db := getTestDB()
|
db := getTestDB()
|
||||||
|
|
||||||
|
@ -319,7 +269,7 @@ func TestDBSScan(t *testing.T) {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.SScan(nil, 1, true, ""); err != nil {
|
if v, err := db.Scan(SET, nil, 1, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 1 {
|
} else if len(v) != 1 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -327,7 +277,7 @@ func TestDBSScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
t.Fatal("invalid value ", string(v[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.SScan(k1, 2, true, ""); err != nil {
|
if v, err := db.Scan(SET, k1, 2, true, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
@ -337,7 +287,7 @@ func TestDBSScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.SScan(k1, 2, false, ""); err != nil {
|
if v, err := db.Scan(SET, k1, 2, false, ""); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(v) != 2 {
|
} else if len(v) != 2 {
|
||||||
t.Fatal("invalid length ", len(v))
|
t.Fatal("invalid length ", len(v))
|
||||||
|
|
|
@ -922,16 +922,6 @@ func (db *DB) BPersist(key []byte) (int64, error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
|
||||||
return db.scan(BitMetaType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) BRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
|
||||||
return db.revscan(BitMetaType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) bFlush() (drop int64, err error) {
|
func (db *DB) bFlush() (drop int64, err error) {
|
||||||
t := db.binBatch
|
t := db.binBatch
|
||||||
t.Lock()
|
t.Lock()
|
||||||
|
|
|
@ -460,14 +460,6 @@ func (db *DB) hFlush() (drop int64, err error) {
|
||||||
return db.flushType(t, HashType)
|
return db.flushType(t, HashType)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) HScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.scan(HSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) HRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.revscan(HSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) HExpire(key []byte, duration int64) (int64, error) {
|
func (db *DB) HExpire(key []byte, duration int64) (int64, error) {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return 0, errExpireValue
|
return 0, errExpireValue
|
||||||
|
|
|
@ -114,7 +114,7 @@ func TestHFlush(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.HScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(HASH, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 2000 {
|
} else if len(v) != 2000 {
|
||||||
t.Fatal("invalid value ", len(v))
|
t.Fatal("invalid value ", len(v))
|
||||||
|
@ -135,7 +135,7 @@ func TestHFlush(t *testing.T) {
|
||||||
t.Fatal("invalid value ", n)
|
t.Fatal("invalid value ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.HScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(HASH, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal("invalid value length ", len(v))
|
t.Fatal("invalid value length ", len(v))
|
||||||
|
|
|
@ -347,16 +347,6 @@ func (db *DB) flush() (drop int64, err error) {
|
||||||
return db.flushType(t, KVType)
|
return db.flushType(t, KVType)
|
||||||
}
|
}
|
||||||
|
|
||||||
//if inclusive is true, scan range [key, inf) else (key, inf)
|
|
||||||
func (db *DB) Scan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.scan(KVType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
//if inclusive is true, revscan range (-inf, key] else (inf, key)
|
|
||||||
func (db *DB) RevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.revscan(KVType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) Expire(key []byte, duration int64) (int64, error) {
|
func (db *DB) Expire(key []byte, duration int64) (int64, error) {
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return 0, errExpireValue
|
return 0, errExpireValue
|
||||||
|
|
|
@ -282,7 +282,7 @@ func TestKVFlush(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(KV, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 2000 {
|
} else if len(v) != 2000 {
|
||||||
t.Fatal("invalid value ", len(v))
|
t.Fatal("invalid value ", len(v))
|
||||||
|
@ -303,7 +303,7 @@ func TestKVFlush(t *testing.T) {
|
||||||
t.Fatal("invalid value ", n)
|
t.Fatal("invalid value ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.Scan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(KV, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal("invalid value length ", len(v))
|
t.Fatal("invalid value length ", len(v))
|
||||||
|
|
|
@ -480,14 +480,6 @@ func (db *DB) LPersist(key []byte) (int64, error) {
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) LScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.scan(LMetaType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) LRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.revscan(LMetaType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) lEncodeMinKey() []byte {
|
func (db *DB) lEncodeMinKey() []byte {
|
||||||
return db.lEncodeMetaKey(nil)
|
return db.lEncodeMetaKey(nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ func TestLFlush(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.LScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(LIST, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 2000 {
|
} else if len(v) != 2000 {
|
||||||
t.Fatal("invalid value ", len(v))
|
t.Fatal("invalid value ", len(v))
|
||||||
|
@ -157,7 +157,7 @@ func TestLFlush(t *testing.T) {
|
||||||
t.Fatal("invalid value ", n)
|
t.Fatal("invalid value ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.LScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(LIST, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal("invalid value length ", len(v))
|
t.Fatal("invalid value length ", len(v))
|
||||||
|
|
|
@ -607,11 +607,3 @@ func (db *DB) SPersist(key []byte) (int64, error) {
|
||||||
err = t.Commit()
|
err = t.Commit()
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) SScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.scan(SSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) SRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.revscan(SSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
|
@ -352,7 +352,7 @@ func TestSFlush(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.SScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(SET, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 2000 {
|
} else if len(v) != 2000 {
|
||||||
t.Fatal("invalid value ", len(v))
|
t.Fatal("invalid value ", len(v))
|
||||||
|
@ -364,7 +364,7 @@ func TestSFlush(t *testing.T) {
|
||||||
t.Fatal("invalid value ", n)
|
t.Fatal("invalid value ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.SScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(SET, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal("invalid value length ", len(v))
|
t.Fatal("invalid value length ", len(v))
|
||||||
|
|
|
@ -936,14 +936,6 @@ func (db *DB) ZInterStore(destKey []byte, srcKeys [][]byte, weights []int64, agg
|
||||||
return n, nil
|
return n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) ZScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.scan(ZSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) ZRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
|
||||||
return db.revscan(ZSizeType, key, count, inclusive, match)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (db *DB) ZRangeByLex(key []byte, min []byte, max []byte, rangeType uint8, offset int, count int) ([][]byte, error) {
|
func (db *DB) ZRangeByLex(key []byte, min []byte, max []byte, rangeType uint8, offset int, count int) ([][]byte, error) {
|
||||||
if min == nil {
|
if min == nil {
|
||||||
min = db.zEncodeStartSetKey(key)
|
min = db.zEncodeStartSetKey(key)
|
||||||
|
|
|
@ -391,7 +391,7 @@ func TestZScan(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.ZScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(ZSET, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 2000 {
|
} else if len(v) != 2000 {
|
||||||
t.Fatal("invalid value ", len(v))
|
t.Fatal("invalid value ", len(v))
|
||||||
|
@ -403,7 +403,7 @@ func TestZScan(t *testing.T) {
|
||||||
t.Fatal("invalid value ", n)
|
t.Fatal("invalid value ", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
if v, err := db.ZScan(nil, 3000, true, ""); err != nil {
|
if v, err := db.Scan(ZSET, nil, 3000, true, ""); err != nil {
|
||||||
t.Fatal(err.Error())
|
t.Fatal(err.Error())
|
||||||
} else if len(v) != 0 {
|
} else if len(v) != 0 {
|
||||||
t.Fatal("invalid value length ", len(v))
|
t.Fatal("invalid value length ", len(v))
|
||||||
|
|
|
@ -274,14 +274,6 @@ func bpersistCommand(c *client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bxscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.BScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func bxrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.BRevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
register("bget", bgetCommand)
|
register("bget", bgetCommand)
|
||||||
register("bdelete", bdeleteCommand)
|
register("bdelete", bdeleteCommand)
|
||||||
|
@ -294,8 +286,4 @@ func init() {
|
||||||
register("bexpireat", bexpireAtCommand)
|
register("bexpireat", bexpireAtCommand)
|
||||||
register("bttl", bttlCommand)
|
register("bttl", bttlCommand)
|
||||||
register("bpersist", bpersistCommand)
|
register("bpersist", bpersistCommand)
|
||||||
register("bxscan", bxscanCommand)
|
|
||||||
register("bxrevscan", bxrevscanCommand)
|
|
||||||
register("xbscan", bxscanCommand)
|
|
||||||
register("xbrevscan", bxrevscanCommand)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -292,14 +292,6 @@ func hpersistCommand(c *client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func hxscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.HScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func hxrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.HRevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func xhexistsCommand(c *client) error {
|
func xhexistsCommand(c *client) error {
|
||||||
args := c.args
|
args := c.args
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
|
@ -334,9 +326,5 @@ func init() {
|
||||||
register("hexpireat", hexpireAtCommand)
|
register("hexpireat", hexpireAtCommand)
|
||||||
register("httl", httlCommand)
|
register("httl", httlCommand)
|
||||||
register("hpersist", hpersistCommand)
|
register("hpersist", hpersistCommand)
|
||||||
register("hxscan", hxscanCommand)
|
|
||||||
register("hxrevscan", hxrevscanCommand)
|
|
||||||
register("xhscan", hxscanCommand)
|
|
||||||
register("xhrevscan", hxrevscanCommand)
|
|
||||||
register("xhexists", xhexistsCommand)
|
register("xhexists", xhexistsCommand)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/siddontang/go/hack"
|
|
||||||
"github.com/siddontang/ledisdb/ledis"
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// func getCommand(c *client) error {
|
// func getCommand(c *client) error {
|
||||||
|
@ -315,82 +313,6 @@ func persistCommand(c *client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseScanArgs(c *client) (key []byte, match string, count int, err error) {
|
|
||||||
args := c.args
|
|
||||||
count = 10
|
|
||||||
|
|
||||||
switch len(args) {
|
|
||||||
case 0:
|
|
||||||
key = nil
|
|
||||||
return
|
|
||||||
case 1, 3, 5:
|
|
||||||
key = args[0]
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
err = ErrCmdParams
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(args) == 3 {
|
|
||||||
switch strings.ToLower(hack.String(args[1])) {
|
|
||||||
case "match":
|
|
||||||
match = hack.String(args[2])
|
|
||||||
case "count":
|
|
||||||
count, err = strconv.Atoi(hack.String(args[2]))
|
|
||||||
default:
|
|
||||||
err = ErrCmdParams
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if len(args) == 5 {
|
|
||||||
if strings.ToLower(hack.String(args[1])) != "match" {
|
|
||||||
err = ErrCmdParams
|
|
||||||
return
|
|
||||||
} else if strings.ToLower(hack.String(args[3])) != "count" {
|
|
||||||
err = ErrCmdParams
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
match = hack.String(args[2])
|
|
||||||
count, err = strconv.Atoi(hack.String(args[4]))
|
|
||||||
}
|
|
||||||
|
|
||||||
if count <= 0 {
|
|
||||||
err = ErrCmdParams
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func xscanGeneric(c *client,
|
|
||||||
f func(key []byte, count int, inclusive bool, match string) ([][]byte, error)) error {
|
|
||||||
key, match, count, err := parseScanArgs(c)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if ay, err := f(key, count, false, match); err != nil {
|
|
||||||
return err
|
|
||||||
} else {
|
|
||||||
data := make([]interface{}, 2)
|
|
||||||
if len(ay) < count {
|
|
||||||
data[0] = []byte("")
|
|
||||||
} else {
|
|
||||||
data[0] = ay[len(ay)-1]
|
|
||||||
}
|
|
||||||
data[1] = ay
|
|
||||||
c.resp.writeArray(data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func xscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.Scan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func xrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.RevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendCommand(c *client) error {
|
func appendCommand(c *client) error {
|
||||||
args := c.args
|
args := c.args
|
||||||
if len(args) != 2 {
|
if len(args) != 2 {
|
||||||
|
@ -619,6 +541,4 @@ func init() {
|
||||||
register("expireat", expireAtCommand)
|
register("expireat", expireAtCommand)
|
||||||
register("ttl", ttlCommand)
|
register("ttl", ttlCommand)
|
||||||
register("persist", persistCommand)
|
register("persist", persistCommand)
|
||||||
register("xscan", xscanCommand)
|
|
||||||
register("xrevscan", xrevscanCommand)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -231,14 +231,6 @@ func lpersistCommand(c *client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lxscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.LScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func lxrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.LRevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func blpopCommand(c *client) error {
|
func blpopCommand(c *client) error {
|
||||||
keys, timeout, err := lParseBPopArgs(c)
|
keys, timeout, err := lParseBPopArgs(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -317,9 +309,5 @@ func init() {
|
||||||
register("lexpireat", lexpireAtCommand)
|
register("lexpireat", lexpireAtCommand)
|
||||||
register("lttl", lttlCommand)
|
register("lttl", lttlCommand)
|
||||||
register("lpersist", lpersistCommand)
|
register("lpersist", lpersistCommand)
|
||||||
register("lxscan", lxscanCommand)
|
|
||||||
register("lxrevscan", lxrevscanCommand)
|
|
||||||
register("xlscan", lxscanCommand)
|
|
||||||
register("xlrevscan", lxrevscanCommand)
|
|
||||||
register("xlexists", xlexistsCommand)
|
register("xlexists", xlexistsCommand)
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,15 +165,15 @@ func xttl(db *ledis.DB, tp string, key []byte) (int64, error) {
|
||||||
func xscan(db *ledis.DB, tp string, count int) ([][]byte, error) {
|
func xscan(db *ledis.DB, tp string, count int) ([][]byte, error) {
|
||||||
switch strings.ToUpper(tp) {
|
switch strings.ToUpper(tp) {
|
||||||
case "KV":
|
case "KV":
|
||||||
return db.Scan(nil, count, false, "")
|
return db.Scan(KV, nil, count, false, "")
|
||||||
case "HASH":
|
case "HASH":
|
||||||
return db.HScan(nil, count, false, "")
|
return db.Scan(HASH, nil, count, false, "")
|
||||||
case "LIST":
|
case "LIST":
|
||||||
return db.LScan(nil, count, false, "")
|
return db.Scan(LIST, nil, count, false, "")
|
||||||
case "SET":
|
case "SET":
|
||||||
return db.SScan(nil, count, false, "")
|
return db.Scan(SET, nil, count, false, "")
|
||||||
case "ZSET":
|
case "ZSET":
|
||||||
return db.ZScan(nil, count, false, "")
|
return db.Scan(ZSET, nil, count, false, "")
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("invalid key type %s", tp)
|
return nil, fmt.Errorf("invalid key type %s", tp)
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,8 @@ func checkDataEqual(master *App, slave *App) error {
|
||||||
mdb, _ := master.ldb.Select(0)
|
mdb, _ := master.ldb.Select(0)
|
||||||
sdb, _ := slave.ldb.Select(0)
|
sdb, _ := slave.ldb.Select(0)
|
||||||
|
|
||||||
mkeys, _ := mdb.Scan(nil, 100, true, "")
|
mkeys, _ := mdb.Scan(KV, nil, 100, true, "")
|
||||||
skeys, _ := sdb.Scan(nil, 100, true, "")
|
skeys, _ := sdb.Scan(KV, nil, 100, true, "")
|
||||||
|
|
||||||
if len(mkeys) != len(skeys) {
|
if len(mkeys) != len(skeys) {
|
||||||
return fmt.Errorf("keys number not equal %d != %d", len(mkeys), len(skeys))
|
return fmt.Errorf("keys number not equal %d != %d", len(mkeys), len(skeys))
|
||||||
|
|
|
@ -0,0 +1,101 @@
|
||||||
|
package server
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/siddontang/go/hack"
|
||||||
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// XSCAN type cursor [MATCH match] [COUNT count] [ASC|DESC]
|
||||||
|
func xscanCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
|
||||||
|
if len(args) < 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataType ledis.DataType
|
||||||
|
switch strings.ToUpper(hack.String(args[0])) {
|
||||||
|
case "KV":
|
||||||
|
dataType = ledis.KV
|
||||||
|
case "HASH":
|
||||||
|
dataType = ledis.HASH
|
||||||
|
case "LIST":
|
||||||
|
dataType = ledis.LIST
|
||||||
|
case "SET":
|
||||||
|
dataType = ledis.SET
|
||||||
|
case "ZSET":
|
||||||
|
dataType = ledis.ZSET
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid key type %s", args[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor := args[1]
|
||||||
|
|
||||||
|
args = args[2:]
|
||||||
|
|
||||||
|
match := ""
|
||||||
|
count := 10
|
||||||
|
|
||||||
|
desc := false
|
||||||
|
|
||||||
|
var err error
|
||||||
|
|
||||||
|
for i := 0; i < len(args); {
|
||||||
|
switch strings.ToUpper(hack.String(args[i])) {
|
||||||
|
case "MATCH":
|
||||||
|
if i+1 >= len(args) {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
match = hack.String(args[i+1])
|
||||||
|
i = i + 2
|
||||||
|
case "COUNT":
|
||||||
|
if i+1 >= len(args) {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
count, err = strconv.Atoi(hack.String(args[i+1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
i = i + 2
|
||||||
|
case "ASC":
|
||||||
|
desc = false
|
||||||
|
i++
|
||||||
|
case "DESC":
|
||||||
|
desc = true
|
||||||
|
i++
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid argument %s", args[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var ay [][]byte
|
||||||
|
if !desc {
|
||||||
|
ay, err = c.db.Scan(dataType, cursor, count, false, match)
|
||||||
|
} else {
|
||||||
|
ay, err = c.db.RevScan(dataType, cursor, count, false, match)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make([]interface{}, 2)
|
||||||
|
if len(ay) < count {
|
||||||
|
data[0] = []byte("")
|
||||||
|
} else {
|
||||||
|
data[0] = ay[len(ay)-1]
|
||||||
|
}
|
||||||
|
data[1] = ay
|
||||||
|
c.resp.writeArray(data)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
register("xscan", xscanCommand)
|
||||||
|
}
|
|
@ -53,8 +53,8 @@ func checkScanValues(t *testing.T, ay interface{}, values ...int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkScan(t *testing.T, c *ledis.Client, cmd string) {
|
func checkScan(t *testing.T, c *ledis.Client, tp string) {
|
||||||
if ay, err := ledis.Values(c.Do(cmd, "", "count", 5)); err != nil {
|
if ay, err := ledis.Values(c.Do("XSCAN", tp, "", "count", 5)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(ay) != 2 {
|
} else if len(ay) != 2 {
|
||||||
t.Fatal(len(ay))
|
t.Fatal(len(ay))
|
||||||
|
@ -64,7 +64,7 @@ func checkScan(t *testing.T, c *ledis.Client, cmd string) {
|
||||||
checkScanValues(t, ay[1], 0, 1, 2, 3, 4)
|
checkScanValues(t, ay[1], 0, 1, 2, 3, 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ay, err := ledis.Values(c.Do(cmd, "4", "count", 6)); err != nil {
|
if ay, err := ledis.Values(c.Do("XSCAN", tp, "4", "count", 6)); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(ay) != 2 {
|
} else if len(ay) != 2 {
|
||||||
t.Fatal(len(ay))
|
t.Fatal(len(ay))
|
||||||
|
@ -76,8 +76,8 @@ func checkScan(t *testing.T, c *ledis.Client, cmd string) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkRevScan(t *testing.T, c *ledis.Client, cmd string) {
|
func checkRevScan(t *testing.T, c *ledis.Client, tp string) {
|
||||||
if ay, err := ledis.Values(c.Do(cmd, "", "count", 5)); err != nil {
|
if ay, err := ledis.Values(c.Do("XSCAN", tp, "", "count", 5, "DESC")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(ay) != 2 {
|
} else if len(ay) != 2 {
|
||||||
t.Fatal(len(ay))
|
t.Fatal(len(ay))
|
||||||
|
@ -87,7 +87,7 @@ func checkRevScan(t *testing.T, c *ledis.Client, cmd string) {
|
||||||
checkScanValues(t, ay[1], 9, 8, 7, 6, 5)
|
checkScanValues(t, ay[1], 9, 8, 7, 6, 5)
|
||||||
}
|
}
|
||||||
|
|
||||||
if ay, err := ledis.Values(c.Do(cmd, "5", "count", 6)); err != nil {
|
if ay, err := ledis.Values(c.Do("XSCAN", tp, "5", "count", 6, "DESC")); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
} else if len(ay) != 2 {
|
} else if len(ay) != 2 {
|
||||||
t.Fatal(len(ay))
|
t.Fatal(len(ay))
|
||||||
|
@ -106,8 +106,8 @@ func testKVScan(t *testing.T, c *ledis.Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScan(t, c, "xscan")
|
checkScan(t, c, "KV")
|
||||||
checkRevScan(t, c, "xrevscan")
|
checkRevScan(t, c, "KV")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testHashScan(t *testing.T, c *ledis.Client) {
|
func testHashScan(t *testing.T, c *ledis.Client) {
|
||||||
|
@ -117,8 +117,8 @@ func testHashScan(t *testing.T, c *ledis.Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScan(t, c, "xhscan")
|
checkScan(t, c, "HASH")
|
||||||
checkRevScan(t, c, "xhrevscan")
|
checkRevScan(t, c, "HASH")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testListScan(t *testing.T, c *ledis.Client) {
|
func testListScan(t *testing.T, c *ledis.Client) {
|
||||||
|
@ -128,8 +128,8 @@ func testListScan(t *testing.T, c *ledis.Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScan(t, c, "xlscan")
|
checkScan(t, c, "LIST")
|
||||||
checkRevScan(t, c, "xlrevscan")
|
checkRevScan(t, c, "LIST")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testZSetScan(t *testing.T, c *ledis.Client) {
|
func testZSetScan(t *testing.T, c *ledis.Client) {
|
||||||
|
@ -139,8 +139,8 @@ func testZSetScan(t *testing.T, c *ledis.Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScan(t, c, "zxscan")
|
checkScan(t, c, "ZSET")
|
||||||
checkRevScan(t, c, "zxrevscan")
|
checkRevScan(t, c, "ZSET")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSetScan(t *testing.T, c *ledis.Client) {
|
func testSetScan(t *testing.T, c *ledis.Client) {
|
||||||
|
@ -150,6 +150,6 @@ func testSetScan(t *testing.T, c *ledis.Client) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkScan(t, c, "xsscan")
|
checkScan(t, c, "SET")
|
||||||
checkRevScan(t, c, "xsrevscan")
|
checkRevScan(t, c, "SET")
|
||||||
}
|
}
|
|
@ -262,14 +262,6 @@ func spersistCommand(c *client) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sxscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.SScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func sxrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.SRevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func xsexistsCommand(c *client) error {
|
func xsexistsCommand(c *client) error {
|
||||||
args := c.args
|
args := c.args
|
||||||
if len(args) != 1 {
|
if len(args) != 1 {
|
||||||
|
@ -301,10 +293,6 @@ func init() {
|
||||||
register("sexpireat", sexpireAtCommand)
|
register("sexpireat", sexpireAtCommand)
|
||||||
register("sttl", sttlCommand)
|
register("sttl", sttlCommand)
|
||||||
register("spersist", spersistCommand)
|
register("spersist", spersistCommand)
|
||||||
register("sxscan", sxscanCommand)
|
|
||||||
register("sxrevscan", sxrevscanCommand)
|
|
||||||
register("xsscan", sxscanCommand)
|
|
||||||
register("xsrevscan", sxrevscanCommand)
|
|
||||||
register("xsexists", xsexistsCommand)
|
register("xsexists", xsexistsCommand)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -641,14 +641,6 @@ func zinterstoreCommand(c *client) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func zxscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.ZScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zxrevscanCommand(c *client) error {
|
|
||||||
return xscanGeneric(c, c.db.ZRevScan)
|
|
||||||
}
|
|
||||||
|
|
||||||
func zparseMemberRange(minBuf []byte, maxBuf []byte) (min []byte, max []byte, rangeType uint8, err error) {
|
func zparseMemberRange(minBuf []byte, maxBuf []byte) (min []byte, max []byte, rangeType uint8, err error) {
|
||||||
rangeType = store.RangeClose
|
rangeType = store.RangeClose
|
||||||
if strings.ToLower(hack.String(minBuf)) == "-" {
|
if strings.ToLower(hack.String(minBuf)) == "-" {
|
||||||
|
@ -815,9 +807,5 @@ func init() {
|
||||||
register("zexpireat", zexpireAtCommand)
|
register("zexpireat", zexpireAtCommand)
|
||||||
register("zttl", zttlCommand)
|
register("zttl", zttlCommand)
|
||||||
register("zpersist", zpersistCommand)
|
register("zpersist", zpersistCommand)
|
||||||
register("zxscan", zxscanCommand)
|
|
||||||
register("zxrevscan", zxrevscanCommand)
|
|
||||||
register("xzscan", zxscanCommand)
|
|
||||||
register("xzrevscan", zxrevscanCommand)
|
|
||||||
register("xzexists", xzexistsCommand)
|
register("xzexists", xzexistsCommand)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/siddontang/ledisdb/ledis"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -26,12 +27,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
KV = iota
|
KV ledis.DataType = ledis.KV
|
||||||
LIST
|
LIST = ledis.LIST
|
||||||
HASH
|
HASH = ledis.HASH
|
||||||
SET
|
SET = ledis.SET
|
||||||
ZSET
|
ZSET = ledis.ZSET
|
||||||
BIT
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
Loading…
Reference in New Issue