mirror of https://github.com/ledisdb/ledisdb.git
Merge branch 'develop'
This commit is contained in:
commit
f18e58c0d0
3
Makefile
3
Makefile
|
@ -33,3 +33,6 @@ test_store:
|
||||||
|
|
||||||
test_rpl:
|
test_rpl:
|
||||||
$(GO) test --race -tags '$(GO_BUILD_TAGS)' ./rpl
|
$(GO) test --race -tags '$(GO_BUILD_TAGS)' ./rpl
|
||||||
|
|
||||||
|
fmt:
|
||||||
|
go fmt ./...
|
|
@ -1,7 +1,8 @@
|
||||||
//This file was generated by .tools/generate_commands.py on Tue Feb 03 2015 14:21:53 +0800
|
//This file was generated by .tools/generate_commands.py on Fri Feb 06 2015 09:15:18 +0800
|
||||||
package main
|
package main
|
||||||
|
|
||||||
var helpCommands = [][]string{
|
var helpCommands = [][]string{
|
||||||
|
{"APPEND", "key value", "KV"},
|
||||||
{"BCOUNT", "key [start end]", "Bitmap"},
|
{"BCOUNT", "key [start end]", "Bitmap"},
|
||||||
{"BDELETE", "key", "ZSet"},
|
{"BDELETE", "key", "ZSet"},
|
||||||
{"BEGIN", "-", "Transaction"},
|
{"BEGIN", "-", "Transaction"},
|
||||||
|
@ -9,6 +10,9 @@ var helpCommands = [][]string{
|
||||||
{"BEXPIREAT", "key timestamp", "Bitmap"},
|
{"BEXPIREAT", "key timestamp", "Bitmap"},
|
||||||
{"BGET", "key", "Bitmap"},
|
{"BGET", "key", "Bitmap"},
|
||||||
{"BGETBIT", "key offset", "Bitmap"},
|
{"BGETBIT", "key offset", "Bitmap"},
|
||||||
|
{"BITCOUNT", "key [start] [end]", "KV"},
|
||||||
|
{"BITOP", "operation destkey key [key ...]", "KV"},
|
||||||
|
{"BITPOS", "key bit [start] [end]", "KV"},
|
||||||
{"BLPOP", "key [key ...] timeout", "List"},
|
{"BLPOP", "key [key ...] timeout", "List"},
|
||||||
{"BMSETBIT", "key offset value [offset value ...]", "Bitmap"},
|
{"BMSETBIT", "key offset value [offset value ...]", "Bitmap"},
|
||||||
{"BOPT", "operation destkey key [key ...]", "Bitmap"},
|
{"BOPT", "operation destkey key [key ...]", "Bitmap"},
|
||||||
|
@ -34,6 +38,8 @@ var helpCommands = [][]string{
|
||||||
{"FLUSHDB", "-", "Server"},
|
{"FLUSHDB", "-", "Server"},
|
||||||
{"FULLSYNC", "[NEW]", "Replication"},
|
{"FULLSYNC", "[NEW]", "Replication"},
|
||||||
{"GET", "key", "KV"},
|
{"GET", "key", "KV"},
|
||||||
|
{"GETBIT", "key offset", "KV"},
|
||||||
|
{"GETRANGE", "key start end", "KV"},
|
||||||
{"GETSET", " key value", "KV"},
|
{"GETSET", " key value", "KV"},
|
||||||
{"HCLEAR", "key", "Hash"},
|
{"HCLEAR", "key", "Hash"},
|
||||||
{"HDEL", "key field [field ...]", "Hash"},
|
{"HDEL", "key field [field ...]", "Hash"},
|
||||||
|
@ -92,8 +98,10 @@ var helpCommands = [][]string{
|
||||||
{"SDUMP", "key", "Set"},
|
{"SDUMP", "key", "Set"},
|
||||||
{"SELECT", "index", "Server"},
|
{"SELECT", "index", "Server"},
|
||||||
{"SET", "key value", "KV"},
|
{"SET", "key value", "KV"},
|
||||||
|
{"SETBIT", "key offset value", "KV"},
|
||||||
{"SETEX", "key seconds value", "KV"},
|
{"SETEX", "key seconds value", "KV"},
|
||||||
{"SETNX", "key value", "KV"},
|
{"SETNX", "key value", "KV"},
|
||||||
|
{"SETRANGE", "key offset value", "KV"},
|
||||||
{"SEXPIRE", "key seconds", "Set"},
|
{"SEXPIRE", "key seconds", "Set"},
|
||||||
{"SEXPIREAT", "key timestamp", "Set"},
|
{"SEXPIREAT", "key timestamp", "Set"},
|
||||||
{"SINTER", "key [key ...]", "Set"},
|
{"SINTER", "key [key ...]", "Set"},
|
||||||
|
@ -104,6 +112,7 @@ var helpCommands = [][]string{
|
||||||
{"SMEMBERS", "key", "Set"},
|
{"SMEMBERS", "key", "Set"},
|
||||||
{"SPERSIST", "key", "Set"},
|
{"SPERSIST", "key", "Set"},
|
||||||
{"SREM", "key member [member ...]", "Set"},
|
{"SREM", "key member [member ...]", "Set"},
|
||||||
|
{"STRLEN", "key", "KV"},
|
||||||
{"STTL", "key", "Set"},
|
{"STTL", "key", "Set"},
|
||||||
{"SUNION", "key [key ...]", "Set"},
|
{"SUNION", "key [key ...]", "Set"},
|
||||||
{"SUNIONSTORE", "destination key [key ...]", "Set"},
|
{"SUNIONSTORE", "destination key [key ...]", "Set"},
|
||||||
|
|
|
@ -794,5 +794,59 @@
|
||||||
"arguments" : "-",
|
"arguments" : "-",
|
||||||
"group" : "Server",
|
"group" : "Server",
|
||||||
"readonly" : true
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"APPEND": {
|
||||||
|
"arguments" : "key value",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : false
|
||||||
|
},
|
||||||
|
|
||||||
|
"GETRANGE": {
|
||||||
|
"arguments" : "key start end",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SETRANGE": {
|
||||||
|
"arguments" : "key offset value",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : false
|
||||||
|
},
|
||||||
|
|
||||||
|
"STRLEN": {
|
||||||
|
"arguments" : "key",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"BITCOUNT": {
|
||||||
|
"arguments" : "key [start] [end]",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"BITOP": {
|
||||||
|
"arguments" : "operation destkey key [key ...]",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : false
|
||||||
|
},
|
||||||
|
|
||||||
|
"BITPOS": {
|
||||||
|
"arguments" : "key bit [start] [end]",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"GETBIT": {
|
||||||
|
"arguments" : "key offset",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : true
|
||||||
|
},
|
||||||
|
|
||||||
|
"SETBIT": {
|
||||||
|
"arguments" : "key offset value",
|
||||||
|
"group" : "KV",
|
||||||
|
"readonly" : false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,3 +98,10 @@ const (
|
||||||
DBInTransaction uint8 = 0x1
|
DBInTransaction uint8 = 0x1
|
||||||
DBInMulti uint8 = 0x2
|
DBInMulti uint8 = 0x2
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
BitAND = "and"
|
||||||
|
BitOR = "or"
|
||||||
|
BitXOR = "xor"
|
||||||
|
BitNot = "not"
|
||||||
|
)
|
||||||
|
|
|
@ -250,52 +250,52 @@ func TestDBLScan(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDBBScan(t *testing.T) {
|
func TestDBBScan(t *testing.T) {
|
||||||
db := getTestDB()
|
// db := getTestDB()
|
||||||
|
|
||||||
db.bFlush()
|
// db.bFlush()
|
||||||
|
|
||||||
k1 := []byte("k1")
|
// k1 := []byte("k1")
|
||||||
if _, err := db.BSetBit(k1, 1, 1); err != nil {
|
// if _, err := db.BSetBit(k1, 1, 1); err != nil {
|
||||||
t.Fatal(err.Error())
|
// t.Fatal(err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
k2 := []byte("k2")
|
// k2 := []byte("k2")
|
||||||
if _, err := db.BSetBit(k2, 1, 1); err != nil {
|
// if _, err := db.BSetBit(k2, 1, 1); err != nil {
|
||||||
t.Fatal(err.Error())
|
// t.Fatal(err.Error())
|
||||||
}
|
// }
|
||||||
k3 := []byte("k3")
|
// k3 := []byte("k3")
|
||||||
|
|
||||||
if _, err := db.BSetBit(k3, 1, 0); err != nil {
|
// if _, err := db.BSetBit(k3, 1, 0); err != nil {
|
||||||
t.Fatal(err.Error())
|
// t.Fatal(err.Error())
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, err := db.BScan(nil, 1, true, ""); err != nil {
|
// if v, err := db.BScan(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))
|
||||||
} else if string(v[0]) != "k1" {
|
// } else if string(v[0]) != "k1" {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
// t.Fatal("invalid value ", string(v[0]))
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, err := db.BScan(k1, 2, true, ""); err != nil {
|
// if v, err := db.BScan(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))
|
||||||
} else if string(v[0]) != "k1" {
|
// } else if string(v[0]) != "k1" {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
// t.Fatal("invalid value ", string(v[0]))
|
||||||
} else if string(v[1]) != "k2" {
|
// } else if string(v[1]) != "k2" {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
// t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, err := db.BScan(k1, 2, false, ""); err != nil {
|
// if v, err := db.BScan(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))
|
||||||
} else if string(v[0]) != "k2" {
|
// } else if string(v[0]) != "k2" {
|
||||||
t.Fatal("invalid value ", string(v[0]))
|
// t.Fatal("invalid value ", string(v[0]))
|
||||||
} else if string(v[1]) != "k3" {
|
// } else if string(v[1]) != "k3" {
|
||||||
t.Fatal("invalid value ", string(v[1]))
|
// t.Fatal("invalid value ", string(v[1]))
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ledis
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"github.com/siddontang/go/log"
|
||||||
"github.com/siddontang/go/num"
|
"github.com/siddontang/go/num"
|
||||||
"github.com/siddontang/ledisdb/store"
|
"github.com/siddontang/ledisdb/store"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -50,19 +51,6 @@ const (
|
||||||
maxSeq uint32 = uint32((maxByteSize << 3) - 1)
|
maxSeq uint32 = uint32((maxByteSize << 3) - 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
var bitsInByte = [256]int32{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3,
|
|
||||||
4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3,
|
|
||||||
3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,
|
|
||||||
5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4,
|
|
||||||
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4,
|
|
||||||
5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2,
|
|
||||||
2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3,
|
|
||||||
4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
|
||||||
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4,
|
|
||||||
5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
|
|
||||||
6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5,
|
|
||||||
6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}
|
|
||||||
|
|
||||||
var fillBits = [...]uint8{1, 3, 7, 15, 31, 63, 127, 255}
|
var fillBits = [...]uint8{1, 3, 7, 15, 31, 63, 127, 255}
|
||||||
|
|
||||||
var emptySegment []byte = make([]byte, segByteSize, segByteSize)
|
var emptySegment []byte = make([]byte, segByteSize, segByteSize)
|
||||||
|
@ -442,6 +430,8 @@ func (db *DB) bCountSeg(key []byte, seq uint32, soff uint32, eoff uint32) (cnt i
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BGet(key []byte) (data []byte, err error) {
|
func (db *DB) BGet(key []byte) (data []byte, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
if err = checkKeySize(key); err != nil {
|
if err = checkKeySize(key); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -476,6 +466,8 @@ func (db *DB) BGet(key []byte) (data []byte, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BDelete(key []byte) (drop int64, err error) {
|
func (db *DB) BDelete(key []byte) (drop int64, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
if err = checkKeySize(key); err != nil {
|
if err = checkKeySize(key); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -492,6 +484,8 @@ func (db *DB) BDelete(key []byte) (drop int64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BSetBit(key []byte, offset int32, val uint8) (ori uint8, err error) {
|
func (db *DB) BSetBit(key []byte, offset int32, val uint8) (ori uint8, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
if err = checkKeySize(key); err != nil {
|
if err = checkKeySize(key); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -528,6 +522,8 @@ func (db *DB) BSetBit(key []byte, offset int32, val uint8) (ori uint8, err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BMSetBit(key []byte, args ...BitPair) (place int64, err error) {
|
func (db *DB) BMSetBit(key []byte, args ...BitPair) (place int64, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
if err = checkKeySize(key); err != nil {
|
if err = checkKeySize(key); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -608,6 +604,8 @@ func (db *DB) BMSetBit(key []byte, args ...BitPair) (place int64, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BGetBit(key []byte, offset int32) (uint8, error) {
|
func (db *DB) BGetBit(key []byte, offset int32) (uint8, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
if seq, off, err := db.bParseOffset(key, offset); err != nil {
|
if seq, off, err := db.bParseOffset(key, offset); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
@ -631,6 +629,8 @@ func (db *DB) BGetBit(key []byte, offset int32) (uint8, error) {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
func (db *DB) BCount(key []byte, start int32, end int32) (cnt int32, err error) {
|
func (db *DB) BCount(key []byte, start int32, end int32) (cnt int32, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
var sseq, soff uint32
|
var sseq, soff uint32
|
||||||
if sseq, soff, err = db.bParseOffset(key, start); err != nil {
|
if sseq, soff, err = db.bParseOffset(key, start); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -686,6 +686,8 @@ func (db *DB) BCount(key []byte, start int32, end int32) (cnt int32, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BTail(key []byte) (int32, error) {
|
func (db *DB) BTail(key []byte) (int32, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
// effective length of data, the highest bit-pos set in history
|
// effective length of data, the highest bit-pos set in history
|
||||||
tailSeq, tailOff, err := db.bGetMeta(key)
|
tailSeq, tailOff, err := db.bGetMeta(key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -701,6 +703,8 @@ func (db *DB) BTail(key []byte) (int32, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32, err error) {
|
func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32, err error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
|
|
||||||
// blen -
|
// blen -
|
||||||
// the total bit size of data stored in destination key,
|
// the total bit size of data stored in destination key,
|
||||||
// that is equal to the size of the longest input string.
|
// that is equal to the size of the longest input string.
|
||||||
|
@ -865,6 +869,7 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BExpire(key []byte, duration int64) (int64, error) {
|
func (db *DB) BExpire(key []byte, duration int64) (int64, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
if duration <= 0 {
|
if duration <= 0 {
|
||||||
return 0, errExpireValue
|
return 0, errExpireValue
|
||||||
}
|
}
|
||||||
|
@ -877,6 +882,7 @@ func (db *DB) BExpire(key []byte, duration int64) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BExpireAt(key []byte, when int64) (int64, error) {
|
func (db *DB) BExpireAt(key []byte, when int64) (int64, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
if when <= time.Now().Unix() {
|
if when <= time.Now().Unix() {
|
||||||
return 0, errExpireValue
|
return 0, errExpireValue
|
||||||
}
|
}
|
||||||
|
@ -889,6 +895,7 @@ func (db *DB) BExpireAt(key []byte, when int64) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BTTL(key []byte) (int64, error) {
|
func (db *DB) BTTL(key []byte) (int64, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
if err := checkKeySize(key); err != nil {
|
if err := checkKeySize(key); err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
@ -897,6 +904,7 @@ func (db *DB) BTTL(key []byte) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BPersist(key []byte) (int64, error) {
|
func (db *DB) BPersist(key []byte) (int64, error) {
|
||||||
|
log.Error("bitmap type will be deprecated later, please use bit operations in kv type")
|
||||||
if err := checkKeySize(key); err != nil {
|
if err := checkKeySize(key); err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
@ -915,10 +923,12 @@ func (db *DB) BPersist(key []byte) (int64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
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)
|
return db.scan(BitMetaType, key, count, inclusive, match)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) BRevScan(key []byte, count int, inclusive bool, match string) ([][]byte, error) {
|
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)
|
return db.revscan(BitMetaType, key, count, inclusive, match)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
1148
ledis/t_bit_test.go
1148
ledis/t_bit_test.go
File diff suppressed because it is too large
Load Diff
375
ledis/t_kv.go
375
ledis/t_kv.go
|
@ -1,9 +1,12 @@
|
||||||
package ledis
|
package ledis
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/siddontang/go/num"
|
"github.com/siddontang/go/num"
|
||||||
"github.com/siddontang/ledisdb/store"
|
"github.com/siddontang/ledisdb/store"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -394,3 +397,375 @@ func (db *DB) Persist(key []byte) (int64, error) {
|
||||||
err = t.Commit()
|
err = t.Commit()
|
||||||
return n, err
|
return n, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) SetRange(key []byte, offset int, value []byte) (int64, error) {
|
||||||
|
if len(value) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else if len(value)+offset > MaxValueSize {
|
||||||
|
return 0, errValueSize
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
|
||||||
|
t := db.kvBatch
|
||||||
|
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
oldValue, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
extra := offset + len(value) - len(oldValue)
|
||||||
|
if extra > 0 {
|
||||||
|
oldValue = append(oldValue, make([]byte, extra)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
copy(oldValue[offset:], value)
|
||||||
|
|
||||||
|
t.Put(key, oldValue)
|
||||||
|
|
||||||
|
if err := t.Commit(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(len(oldValue)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getRange(start int, end int, valLen int) (int, int) {
|
||||||
|
if start < 0 {
|
||||||
|
start = valLen + start
|
||||||
|
}
|
||||||
|
|
||||||
|
if end < 0 {
|
||||||
|
end = valLen + end
|
||||||
|
}
|
||||||
|
|
||||||
|
if start < 0 {
|
||||||
|
start = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if end < 0 {
|
||||||
|
end = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if end >= valLen {
|
||||||
|
end = valLen - 1
|
||||||
|
}
|
||||||
|
return start, end
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetRange(key []byte, start int, end int) ([]byte, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
valLen := len(value)
|
||||||
|
|
||||||
|
start, end = getRange(start, end, valLen)
|
||||||
|
|
||||||
|
if start > end {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return value[start : end+1], nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) StrLen(key []byte) (int64, error) {
|
||||||
|
s, err := db.GetSlice(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
n := s.Size()
|
||||||
|
s.Free()
|
||||||
|
return int64(n), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) Append(key []byte, value []byte) (int64, error) {
|
||||||
|
if len(value) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
|
||||||
|
t := db.kvBatch
|
||||||
|
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
oldValue, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(oldValue)+len(value) > MaxValueSize {
|
||||||
|
return 0, errValueSize
|
||||||
|
}
|
||||||
|
|
||||||
|
oldValue = append(oldValue, value...)
|
||||||
|
|
||||||
|
t.Put(key, oldValue)
|
||||||
|
|
||||||
|
if err := t.Commit(); err != nil {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(len(oldValue)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) BitOP(op string, destKey []byte, srcKeys ...[]byte) (int64, error) {
|
||||||
|
if err := checkKeySize(destKey); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
op = strings.ToLower(op)
|
||||||
|
if len(srcKeys) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
} else if op == BitNot && len(srcKeys) > 1 {
|
||||||
|
return 0, fmt.Errorf("BITOP NOT has only one srckey")
|
||||||
|
} else if len(srcKeys) < 2 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
key := db.encodeKVKey(srcKeys[0])
|
||||||
|
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if op == BitNot {
|
||||||
|
for i := 0; i < len(value); i++ {
|
||||||
|
value[i] ^= value[i]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for j := 1; j < len(srcKeys); j++ {
|
||||||
|
if err := checkKeySize(srcKeys[j]); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(srcKeys[j])
|
||||||
|
ovalue, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(value) < len(ovalue) {
|
||||||
|
value, ovalue = ovalue, value
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < len(ovalue); i++ {
|
||||||
|
switch op {
|
||||||
|
case BitAND:
|
||||||
|
value[i] &= ovalue[i]
|
||||||
|
case BitOR:
|
||||||
|
value[i] |= ovalue[i]
|
||||||
|
case BitXOR:
|
||||||
|
value[i] ^= ovalue[i]
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("invalid op type: %s", op)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := len(ovalue); i < len(value); i++ {
|
||||||
|
switch op {
|
||||||
|
case BitAND:
|
||||||
|
value[i] &= 0
|
||||||
|
case BitOR:
|
||||||
|
value[i] |= 0
|
||||||
|
case BitXOR:
|
||||||
|
value[i] ^= 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(destKey)
|
||||||
|
|
||||||
|
t := db.kvBatch
|
||||||
|
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
t.Put(key, value)
|
||||||
|
|
||||||
|
if err := t.Commit(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return int64(len(value)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var bitsInByte = [256]int32{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3,
|
||||||
|
4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3,
|
||||||
|
3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4,
|
||||||
|
5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4,
|
||||||
|
3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4,
|
||||||
|
5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2,
|
||||||
|
2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3,
|
||||||
|
4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
|
||||||
|
3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4,
|
||||||
|
5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6,
|
||||||
|
6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5,
|
||||||
|
6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}
|
||||||
|
|
||||||
|
func numberBitCount(i uint32) uint32 {
|
||||||
|
i = i - ((i >> 1) & 0x55555555)
|
||||||
|
i = (i & 0x33333333) + ((i >> 2) & 0x33333333)
|
||||||
|
return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) BitCount(key []byte, start int, end int) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
start, end = getRange(start, end, len(value))
|
||||||
|
value = value[start : end+1]
|
||||||
|
|
||||||
|
var n int64 = 0
|
||||||
|
|
||||||
|
pos := 0
|
||||||
|
for ; pos+4 <= len(value); pos = pos + 4 {
|
||||||
|
n += int64(numberBitCount(binary.BigEndian.Uint32(value[pos : pos+4])))
|
||||||
|
}
|
||||||
|
|
||||||
|
for ; pos < len(value); pos++ {
|
||||||
|
n += int64(bitsInByte[value[pos]])
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) BitPos(key []byte, on int, start int, end int) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on & ^1) != 0 {
|
||||||
|
return 0, fmt.Errorf("bit must be 0 or 1, not %d", on)
|
||||||
|
}
|
||||||
|
|
||||||
|
var skipValue uint8 = 0
|
||||||
|
if on == 0 {
|
||||||
|
skipValue = 0xFF
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
start, end = getRange(start, end, len(value))
|
||||||
|
value = value[start : end+1]
|
||||||
|
|
||||||
|
for i, v := range value {
|
||||||
|
if uint8(v) != skipValue {
|
||||||
|
for j := 0; j < 8; j++ {
|
||||||
|
isNull := uint8(v)&(1<<uint8(7-j)) == 0
|
||||||
|
|
||||||
|
if (on == 1 && !isNull) || (on == 0 && isNull) {
|
||||||
|
return int64((start+i)*8 + j), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) SetBit(key []byte, offset int, on int) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if (on & ^1) != 0 {
|
||||||
|
return 0, fmt.Errorf("bit must be 0 or 1, not %d", on)
|
||||||
|
}
|
||||||
|
|
||||||
|
t := db.kvBatch
|
||||||
|
|
||||||
|
t.Lock()
|
||||||
|
defer t.Unlock()
|
||||||
|
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
byteOffset := int(uint32(offset) >> 3)
|
||||||
|
extra := byteOffset + 1 - len(value)
|
||||||
|
if extra > 0 {
|
||||||
|
value = append(value, make([]byte, extra)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
byteVal := value[byteOffset]
|
||||||
|
bit := 7 - uint8(uint32(offset)&0x7)
|
||||||
|
bitVal := byteVal & (1 << bit)
|
||||||
|
|
||||||
|
byteVal &= ^(1 << bit)
|
||||||
|
byteVal |= (uint8(on&0x1) << bit)
|
||||||
|
|
||||||
|
value[byteOffset] = byteVal
|
||||||
|
|
||||||
|
t.Put(key, value)
|
||||||
|
if err := t.Commit(); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if bitVal > 0 {
|
||||||
|
return 1, nil
|
||||||
|
} else {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) GetBit(key []byte, offset int) (int64, error) {
|
||||||
|
if err := checkKeySize(key); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key = db.encodeKVKey(key)
|
||||||
|
|
||||||
|
value, err := db.bucket.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
byteOffset := uint32(offset) >> 3
|
||||||
|
bit := 7 - uint8(uint32(offset)&0x7)
|
||||||
|
|
||||||
|
if byteOffset >= uint32(len(value)) {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
bitVal := value[byteOffset] & (1 << bit)
|
||||||
|
if bitVal > 0 {
|
||||||
|
return 1, nil
|
||||||
|
} else {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -42,6 +42,211 @@ func TestDBKV(t *testing.T) {
|
||||||
t.Fatal(string(v2))
|
t.Fatal(string(v2))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
key3 := []byte("testdb_kv_range")
|
||||||
|
|
||||||
|
if n, err := db.Append(key3, []byte("Hello")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 5 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.Append(key3, []byte(" World")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.StrLen(key3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.GetRange(key3, 0, 4); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "Hello" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.GetRange(key3, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "Hello World" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.GetRange(key3, -5, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "World" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SetRange(key3, 6, []byte("Redis")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.Get(key3); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "Hello Redis" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
key4 := []byte("testdb_kv_range_none")
|
||||||
|
if n, err := db.SetRange(key4, 6, []byte("Redis")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
key5 := []byte("testdb_kv_bit")
|
||||||
|
if n, err := db.SetBit(key5, 7, 1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 0 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.GetBit(key5, 0); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 0 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
if n, err := db.GetBit(key5, 7); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
if n, err := db.GetBit(key5, 100); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 0 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitCount(key5, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitPos(key5, 1, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 7 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.SetBit(key5, 7, 0); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key5, []byte{0xff, 0xf0, 0x00}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitPos(key5, 0, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 12 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key5, []byte{0x00, 0xff, 0xf0}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitPos(key5, 1, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 8 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitPos(key5, 1, 2, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 16 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key5, []byte{0x00, 0x00, 0x00}); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitPos(key5, 1, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != -1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key5, []byte("foobar")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitCount(key5, 0, -1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 26 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitCount(key5, 0, 0); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 4 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitCount(key5, 1, 1); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
key6 := []byte("testdb_kv_bitop_desc")
|
||||||
|
|
||||||
|
if err := db.Set(key4, []byte("foobar")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key5, []byte("abcdef")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitOP(BitAND, key6, key4, key5); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.Get(key6); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "`bc`ab" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := db.Set(key4, []byte("fooba")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitOP(BitOR, key6, key4, key5); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.Get(key6); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "goofef" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := db.BitOP(BitAND, key6, key4, key5); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := db.Get(key6); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if string(v) != "`bc`a\x00" {
|
||||||
|
t.Fatal(string(v))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKVPersist(t *testing.T) {
|
func TestKVPersist(t *testing.T) {
|
||||||
|
|
|
@ -139,7 +139,7 @@ func (c *ttlChecker) setNextCheckTime(when int64, force bool) {
|
||||||
c.Lock()
|
c.Lock()
|
||||||
if force {
|
if force {
|
||||||
c.nc = when
|
c.nc = when
|
||||||
} else if c.nc > when {
|
} else if c.nc > when {
|
||||||
c.nc = when
|
c.nc = when
|
||||||
}
|
}
|
||||||
c.Unlock()
|
c.Unlock()
|
||||||
|
|
|
@ -195,50 +195,50 @@ func setAdaptor(db *DB) *adaptor {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func bitAdaptor(db *DB) *adaptor {
|
// func bitAdaptor(db *DB) *adaptor {
|
||||||
adp := new(adaptor)
|
// adp := new(adaptor)
|
||||||
adp.showIdent = func() string {
|
// adp.showIdent = func() string {
|
||||||
return "bit-adaptor"
|
// return "bit-adaptor"
|
||||||
}
|
// }
|
||||||
|
|
||||||
adp.set = func(k []byte, v []byte) (int64, error) {
|
// adp.set = func(k []byte, v []byte) (int64, error) {
|
||||||
datas := make([]BitPair, 3)
|
// datas := make([]BitPair, 3)
|
||||||
datas[0] = BitPair{0, 1}
|
// datas[0] = BitPair{0, 1}
|
||||||
datas[1] = BitPair{2, 1}
|
// datas[1] = BitPair{2, 1}
|
||||||
datas[2] = BitPair{5, 1}
|
// datas[2] = BitPair{5, 1}
|
||||||
|
|
||||||
if _, err := db.BMSetBit(k, datas...); err != nil {
|
// if _, err := db.BMSetBit(k, datas...); err != nil {
|
||||||
return 0, err
|
// return 0, err
|
||||||
} else {
|
// } else {
|
||||||
return int64(len(datas)), nil
|
// return int64(len(datas)), nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
adp.exists = func(k []byte) (int64, error) {
|
// adp.exists = func(k []byte) (int64, error) {
|
||||||
var start, end int32 = 0, -1
|
// var start, end int32 = 0, -1
|
||||||
if blen, err := db.BCount(k, start, end); err != nil || blen <= 0 {
|
// if blen, err := db.BCount(k, start, end); err != nil || blen <= 0 {
|
||||||
return 0, err
|
// return 0, err
|
||||||
} else {
|
// } else {
|
||||||
return 1, nil
|
// return 1, nil
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
adp.del = db.BDelete
|
// adp.del = db.BDelete
|
||||||
adp.expire = db.BExpire
|
// adp.expire = db.BExpire
|
||||||
adp.expireAt = db.BExpireAt
|
// adp.expireAt = db.BExpireAt
|
||||||
adp.ttl = db.BTTL
|
// adp.ttl = db.BTTL
|
||||||
|
|
||||||
return adp
|
// return adp
|
||||||
}
|
// }
|
||||||
|
|
||||||
func allAdaptors(db *DB) []*adaptor {
|
func allAdaptors(db *DB) []*adaptor {
|
||||||
adps := make([]*adaptor, 6)
|
adps := make([]*adaptor, 5)
|
||||||
adps[0] = kvAdaptor(db)
|
adps[0] = kvAdaptor(db)
|
||||||
adps[1] = listAdaptor(db)
|
adps[1] = listAdaptor(db)
|
||||||
adps[2] = hashAdaptor(db)
|
adps[2] = hashAdaptor(db)
|
||||||
adps[3] = zsetAdaptor(db)
|
adps[3] = zsetAdaptor(db)
|
||||||
adps[4] = setAdaptor(db)
|
adps[4] = setAdaptor(db)
|
||||||
adps[5] = bitAdaptor(db)
|
//adps[5] = bitAdaptor(db)
|
||||||
return adps
|
return adps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,367 +1,367 @@
|
||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
// import (
|
||||||
"github.com/siddontang/ledisdb/client/go/ledis"
|
// "github.com/siddontang/ledisdb/client/go/ledis"
|
||||||
"testing"
|
// "testing"
|
||||||
)
|
// )
|
||||||
|
|
||||||
func TestBit(t *testing.T) {
|
// func TestBit(t *testing.T) {
|
||||||
testBitGetSet(t)
|
// testBitGetSet(t)
|
||||||
testBitMset(t)
|
// testBitMset(t)
|
||||||
testBitCount(t)
|
// testBitCount(t)
|
||||||
testBitOpt(t)
|
// testBitOpt(t)
|
||||||
}
|
// }
|
||||||
|
|
||||||
func testBitGetSet(t *testing.T) {
|
// func testBitGetSet(t *testing.T) {
|
||||||
c := getTestConn()
|
// c := getTestConn()
|
||||||
defer c.Close()
|
// defer c.Close()
|
||||||
|
|
||||||
key := []byte("test_cmd_bin_basic")
|
// key := []byte("test_cmd_bin_basic")
|
||||||
|
|
||||||
// get / set
|
// // get / set
|
||||||
if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
// if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if v != 0 {
|
// } else if v != 0 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if ori, err := ledis.Int(c.Do("bsetbit", key, 1024, 1)); err != nil {
|
// if ori, err := ledis.Int(c.Do("bsetbit", key, 1024, 1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if ori != 0 {
|
// } else if ori != 0 {
|
||||||
t.Fatal(ori)
|
// t.Fatal(ori)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
// if v, err := ledis.Int(c.Do("bgetbit", key, 1024)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if v != 1 {
|
// } else if v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// fetch from revert pos
|
// // fetch from revert pos
|
||||||
c.Do("bsetbit", key, 1000, 1)
|
// c.Do("bsetbit", key, 1000, 1)
|
||||||
|
|
||||||
if v, err := ledis.Int(c.Do("bgetbit", key, -1)); err != nil {
|
// if v, err := ledis.Int(c.Do("bgetbit", key, -1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if v != 1 {
|
// } else if v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, err := ledis.Int(c.Do("bgetbit", key, -25)); err != nil {
|
// if v, err := ledis.Int(c.Do("bgetbit", key, -25)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if v != 1 {
|
// } else if v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// delete
|
// // delete
|
||||||
if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
// if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if drop != 1 {
|
// } else if drop != 1 {
|
||||||
t.Fatal(drop)
|
// t.Fatal(drop)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
// if drop, err := ledis.Int(c.Do("bdelete", key)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if drop != 0 {
|
// } else if drop != 0 {
|
||||||
t.Fatal(drop)
|
// t.Fatal(drop)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func testBitMset(t *testing.T) {
|
// func testBitMset(t *testing.T) {
|
||||||
c := getTestConn()
|
// c := getTestConn()
|
||||||
defer c.Close()
|
// defer c.Close()
|
||||||
|
|
||||||
key := []byte("test_cmd_bin_mset")
|
// key := []byte("test_cmd_bin_mset")
|
||||||
|
|
||||||
if n, err := ledis.Int(
|
// if n, err := ledis.Int(
|
||||||
c.Do("bmsetbit", key,
|
// c.Do("bmsetbit", key,
|
||||||
500, 0,
|
// 500, 0,
|
||||||
100, 1,
|
// 100, 1,
|
||||||
200, 1,
|
// 200, 1,
|
||||||
1000, 1,
|
// 1000, 1,
|
||||||
900, 0,
|
// 900, 0,
|
||||||
500000, 1,
|
// 500000, 1,
|
||||||
600, 0,
|
// 600, 0,
|
||||||
300, 1,
|
// 300, 1,
|
||||||
100000, 1)); err != nil {
|
// 100000, 1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if n != 9 {
|
// } else if n != 9 {
|
||||||
t.Fatal(n)
|
// t.Fatal(n)
|
||||||
}
|
// }
|
||||||
|
|
||||||
fillPos := []int{100, 200, 300, 1000, 100000, 500000}
|
// fillPos := []int{100, 200, 300, 1000, 100000, 500000}
|
||||||
for _, pos := range fillPos {
|
// for _, pos := range fillPos {
|
||||||
v, err := ledis.Int(c.Do("bgetbit", key, pos))
|
// v, err := ledis.Int(c.Do("bgetbit", key, pos))
|
||||||
if err != nil || v != 1 {
|
// if err != nil || v != 1 {
|
||||||
t.Fatal(pos)
|
// t.Fatal(pos)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// err
|
// // err
|
||||||
if n, err := ledis.Int(
|
// if n, err := ledis.Int(
|
||||||
c.Do("bmsetbit", key, 3, 0, 2, 1, 3, 0, 1, 1)); err == nil || n != 0 {
|
// c.Do("bmsetbit", key, 3, 0, 2, 1, 3, 0, 1, 1)); err == nil || n != 0 {
|
||||||
t.Fatal(n) // duplication on pos
|
// t.Fatal(n) // duplication on pos
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func testBitCount(t *testing.T) {
|
// func testBitCount(t *testing.T) {
|
||||||
c := getTestConn()
|
// c := getTestConn()
|
||||||
defer c.Close()
|
// defer c.Close()
|
||||||
|
|
||||||
key := []byte("test_cmd_bin_count")
|
// key := []byte("test_cmd_bin_count")
|
||||||
sum := 0
|
// sum := 0
|
||||||
for pos := 1; pos < 1000000; pos += 10001 {
|
// for pos := 1; pos < 1000000; pos += 10001 {
|
||||||
c.Do("bsetbit", key, pos, 1)
|
// c.Do("bsetbit", key, pos, 1)
|
||||||
sum++
|
// sum++
|
||||||
}
|
// }
|
||||||
|
|
||||||
if n, err := ledis.Int(c.Do("bcount", key)); err != nil {
|
// if n, err := ledis.Int(c.Do("bcount", key)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if n != sum {
|
// } else if n != sum {
|
||||||
t.Fatal(n)
|
// t.Fatal(n)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
func testBitOpt(t *testing.T) {
|
// func testBitOpt(t *testing.T) {
|
||||||
c := getTestConn()
|
// c := getTestConn()
|
||||||
defer c.Close()
|
// defer c.Close()
|
||||||
|
|
||||||
dstk := []byte("bin_op_res")
|
// dstk := []byte("bin_op_res")
|
||||||
kmiss := []byte("bin_op_miss")
|
// kmiss := []byte("bin_op_miss")
|
||||||
|
|
||||||
k0 := []byte("bin_op_0")
|
// k0 := []byte("bin_op_0")
|
||||||
k1 := []byte("bin_op_1")
|
// k1 := []byte("bin_op_1")
|
||||||
c.Do("bmsetbit", k0, 10, 1, 30, 1, 50, 1, 70, 1, 100, 1)
|
// c.Do("bmsetbit", k0, 10, 1, 30, 1, 50, 1, 70, 1, 100, 1)
|
||||||
c.Do("bmsetbit", k1, 20, 1, 40, 1, 60, 1, 80, 1, 100, 1)
|
// c.Do("bmsetbit", k1, 20, 1, 40, 1, 60, 1, 80, 1, 100, 1)
|
||||||
|
|
||||||
// case - lack of args
|
// // case - lack of args
|
||||||
// todo ...
|
// // todo ...
|
||||||
|
|
||||||
// case - 'not' on inexisting key
|
// // case - 'not' on inexisting key
|
||||||
if blen, err := ledis.Int(
|
// if blen, err := ledis.Int(
|
||||||
c.Do("bopt", "not", dstk, kmiss)); err != nil {
|
// c.Do("bopt", "not", dstk, kmiss)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if blen != 0 {
|
// } else if blen != 0 {
|
||||||
t.Fatal(blen)
|
// t.Fatal(blen)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.String(c.Do("bget", dstk)); v != "" {
|
// if v, _ := ledis.String(c.Do("bget", dstk)); v != "" {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// case - 'and', 'or', 'xor' with inexisting key
|
// // case - 'and', 'or', 'xor' with inexisting key
|
||||||
opts := []string{"and", "or", "xor"}
|
// opts := []string{"and", "or", "xor"}
|
||||||
for _, op := range opts {
|
// for _, op := range opts {
|
||||||
if blen, err := ledis.Int(
|
// if blen, err := ledis.Int(
|
||||||
c.Do("bopt", op, dstk, kmiss, k0)); err != nil {
|
// c.Do("bopt", op, dstk, kmiss, k0)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if blen != 0 {
|
// } else if blen != 0 {
|
||||||
t.Fatal(blen)
|
// t.Fatal(blen)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// case - 'and'
|
// // case - 'and'
|
||||||
if blen, err := ledis.Int(
|
// if blen, err := ledis.Int(
|
||||||
c.Do("bopt", "and", dstk, k0, k1)); err != nil {
|
// c.Do("bopt", "and", dstk, k0, k1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if blen != 101 {
|
// } else if blen != 101 {
|
||||||
t.Fatal(blen)
|
// t.Fatal(blen)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 0 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 0 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 0 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 0 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// case - 'or'
|
// // case - 'or'
|
||||||
if blen, err := ledis.Int(
|
// if blen, err := ledis.Int(
|
||||||
c.Do("bopt", "or", dstk, k0, k1)); err != nil {
|
// c.Do("bopt", "or", dstk, k0, k1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if blen != 101 {
|
// } else if blen != 101 {
|
||||||
t.Fatal(blen)
|
// t.Fatal(blen)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// case - 'xor'
|
// // case - 'xor'
|
||||||
if blen, err := ledis.Int(
|
// if blen, err := ledis.Int(
|
||||||
c.Do("bopt", "xor", dstk, k0, k1)); err != nil {
|
// c.Do("bopt", "xor", dstk, k0, k1)); err != nil {
|
||||||
t.Fatal(err)
|
// t.Fatal(err)
|
||||||
} else if blen != 101 {
|
// } else if blen != 101 {
|
||||||
t.Fatal(blen)
|
// t.Fatal(blen)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 0 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 100)); v != 0 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 20)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
// if v, _ := ledis.Int(c.Do("bgetbit", dstk, 40)); v != 1 {
|
||||||
t.Fatal(v)
|
// t.Fatal(v)
|
||||||
}
|
// }
|
||||||
|
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
|
|
||||||
func TestBitErrorParams(t *testing.T) {
|
// func TestBitErrorParams(t *testing.T) {
|
||||||
c := getTestConn()
|
// c := getTestConn()
|
||||||
defer c.Close()
|
// defer c.Close()
|
||||||
|
|
||||||
if _, err := c.Do("bget"); err == nil {
|
// if _, err := c.Do("bget"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bdelete"); err == nil {
|
// if _, err := c.Do("bdelete"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// bsetbit
|
// // bsetbit
|
||||||
if _, err := c.Do("bsetbit"); err == nil {
|
// if _, err := c.Do("bsetbit"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bsetbit", "test_bsetbit"); err == nil {
|
// if _, err := c.Do("bsetbit", "test_bsetbit"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bsetbit", "test_bsetbit", "o", "v"); err == nil {
|
// if _, err := c.Do("bsetbit", "test_bsetbit", "o", "v"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bsetbit", "test_bsetbit", "o", 1); err == nil {
|
// if _, err := c.Do("bsetbit", "test_bsetbit", "o", 1); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if _, err := c.Do("bsetbit", "test_bsetbit", -1, 1); err == nil {
|
// // if _, err := c.Do("bsetbit", "test_bsetbit", -1, 1); err == nil {
|
||||||
// t.Fatal("invalid err of %v", err)
|
// // t.Fatal("invalid err of %v", err)
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
if _, err := c.Do("bsetbit", "test_bsetbit", 1, "v"); err == nil {
|
// if _, err := c.Do("bsetbit", "test_bsetbit", 1, "v"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bsetbit", "test_bsetbit", 1, 2); err == nil {
|
// if _, err := c.Do("bsetbit", "test_bsetbit", 1, 2); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//bgetbit
|
// //bgetbit
|
||||||
if _, err := c.Do("bgetbit", "test_bgetbit"); err == nil {
|
// if _, err := c.Do("bgetbit", "test_bgetbit"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bgetbit", "test_bgetbit", "o"); err == nil {
|
// if _, err := c.Do("bgetbit", "test_bgetbit", "o"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if _, err := c.Do("bgetbit", "test_bgetbit", -1); err == nil {
|
// // if _, err := c.Do("bgetbit", "test_bgetbit", -1); err == nil {
|
||||||
// t.Fatal("invalid err of %v", err)
|
// // t.Fatal("invalid err of %v", err)
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
//bmsetbit
|
// //bmsetbit
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit"); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", 0, 1, 2); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", 0, 1, 2); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", "o", "v"); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", "o", "v"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", "o", 1); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", "o", 1); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if _, err := c.Do("bmsetbit", "test_bmsetbit", -1, 1); err == nil {
|
// // if _, err := c.Do("bmsetbit", "test_bmsetbit", -1, 1); err == nil {
|
||||||
// t.Fatal("invalid err of %v", err)
|
// // t.Fatal("invalid err of %v", err)
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, "v"); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, "v"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, 2); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, 2); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, 0.1); err == nil {
|
// if _, err := c.Do("bmsetbit", "test_bmsetbit", 1, 0.1); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//bcount
|
// //bcount
|
||||||
|
|
||||||
if _, err := c.Do("bcount"); err == nil {
|
// if _, err := c.Do("bcount"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bcount", "a", "b", "c"); err == nil {
|
// if _, err := c.Do("bcount", "a", "b", "c"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bcount", 1, "a"); err == nil {
|
// if _, err := c.Do("bcount", 1, "a"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if _, err := c.Do("bcount", 1); err == nil {
|
// // if _, err := c.Do("bcount", 1); err == nil {
|
||||||
// t.Fatal("invalid err of %v", err)
|
// // t.Fatal("invalid err of %v", err)
|
||||||
// }
|
// // }
|
||||||
|
|
||||||
//bopt
|
// //bopt
|
||||||
if _, err := c.Do("bopt"); err == nil {
|
// if _, err := c.Do("bopt"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bopt", "and", 1); err == nil {
|
// if _, err := c.Do("bopt", "and", 1); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bopt", "x", 1); err == nil {
|
// if _, err := c.Do("bopt", "x", 1); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
if _, err := c.Do("bopt", ""); err == nil {
|
// if _, err := c.Do("bopt", ""); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// 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)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//bexpireat
|
// //bexpireat
|
||||||
if _, err := c.Do("bexpireat", "test_bexpireat"); err == nil {
|
// if _, err := c.Do("bexpireat", "test_bexpireat"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//bttl
|
// //bttl
|
||||||
if _, err := c.Do("bttl"); err == nil {
|
// if _, err := c.Do("bttl"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
//bpersist
|
// //bpersist
|
||||||
if _, err := c.Do("bpersist"); err == nil {
|
// if _, err := c.Do("bpersist"); err == nil {
|
||||||
t.Fatal("invalid err of %v", err)
|
// t.Fatal("invalid err of %v", err)
|
||||||
}
|
// }
|
||||||
|
|
||||||
}
|
// }
|
||||||
|
|
210
server/cmd_kv.go
210
server/cmd_kv.go
|
@ -391,20 +391,230 @@ func xrevscanCommand(c *client) error {
|
||||||
return xscanGeneric(c, c.db.RevScan)
|
return xscanGeneric(c, c.db.RevScan)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) != 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.Append(args[0], args[1]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getrangeCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) != 3 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
start, err := strconv.Atoi(string(args[1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
end, err := strconv.Atoi(string(args[2]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := c.db.GetRange(key, start, end); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeBulk(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func setrangeCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) != 3 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
offset, err := strconv.Atoi(string(args[1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value := args[2]
|
||||||
|
|
||||||
|
if n, err := c.db.SetRange(key, offset, value); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func strlenCommand(c *client) error {
|
||||||
|
if len(c.args) != 1 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.StrLen(c.args[0]); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseBitRange(args [][]byte) (start int, end int, err error) {
|
||||||
|
start = 0
|
||||||
|
end = -1
|
||||||
|
if len(args) > 0 {
|
||||||
|
if start, err = strconv.Atoi(string(args[0])); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(args) == 2 {
|
||||||
|
if end, err = strconv.Atoi(string(args[1])); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func bitcountCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) == 0 || len(args) > 3 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
start, end, err := parseBitRange(args[1:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.BitCount(key, start, end); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bitopCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) < 3 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
op := string(args[0])
|
||||||
|
destKey := args[1]
|
||||||
|
srcKeys := args[2:]
|
||||||
|
|
||||||
|
if n, err := c.db.BitOP(op, destKey, srcKeys...); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func bitposCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) < 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
bit, err := strconv.Atoi(string(args[1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
start, end, err := parseBitRange(args[2:])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.BitPos(key, bit, start, end); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getbitCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) != 2 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
offset, err := strconv.Atoi(string(args[1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.GetBit(key, offset); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setbitCommand(c *client) error {
|
||||||
|
args := c.args
|
||||||
|
if len(args) != 3 {
|
||||||
|
return ErrCmdParams
|
||||||
|
}
|
||||||
|
|
||||||
|
key := args[0]
|
||||||
|
offset, err := strconv.Atoi(string(args[1]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
value, err := strconv.Atoi(string(args[2]))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := c.db.SetBit(key, offset, value); err != nil {
|
||||||
|
return err
|
||||||
|
} else {
|
||||||
|
c.resp.writeInteger(n)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
register("append", appendCommand)
|
||||||
|
register("bitcount", bitcountCommand)
|
||||||
|
register("bitop", bitopCommand)
|
||||||
|
register("bitpos", bitposCommand)
|
||||||
register("decr", decrCommand)
|
register("decr", decrCommand)
|
||||||
register("decrby", decrbyCommand)
|
register("decrby", decrbyCommand)
|
||||||
register("del", delCommand)
|
register("del", delCommand)
|
||||||
register("exists", existsCommand)
|
register("exists", existsCommand)
|
||||||
register("get", getCommand)
|
register("get", getCommand)
|
||||||
|
register("getbit", getbitCommand)
|
||||||
|
register("getrange", getrangeCommand)
|
||||||
register("getset", getsetCommand)
|
register("getset", getsetCommand)
|
||||||
register("incr", incrCommand)
|
register("incr", incrCommand)
|
||||||
register("incrby", incrbyCommand)
|
register("incrby", incrbyCommand)
|
||||||
register("mget", mgetCommand)
|
register("mget", mgetCommand)
|
||||||
register("mset", msetCommand)
|
register("mset", msetCommand)
|
||||||
register("set", setCommand)
|
register("set", setCommand)
|
||||||
|
register("setbit", setbitCommand)
|
||||||
register("setnx", setnxCommand)
|
register("setnx", setnxCommand)
|
||||||
register("setex", setexCommand)
|
register("setex", setexCommand)
|
||||||
|
register("setrange", setrangeCommand)
|
||||||
|
register("strlen", strlenCommand)
|
||||||
register("expire", expireCommand)
|
register("expire", expireCommand)
|
||||||
register("expireat", expireAtCommand)
|
register("expireat", expireAtCommand)
|
||||||
register("ttl", ttlCommand)
|
register("ttl", ttlCommand)
|
||||||
|
|
|
@ -78,6 +78,72 @@ func TestKV(t *testing.T) {
|
||||||
} else if n != 0 {
|
} else if n != 0 {
|
||||||
t.Fatal(n)
|
t.Fatal(n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rangeKey := "range_key"
|
||||||
|
if n, err := ledis.Int(c.Do("append", rangeKey, "Hello ")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("setrange", rangeKey, 6, "Redis")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("strlen", rangeKey)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 11 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := ledis.String(c.Do("getrange", rangeKey, 0, -1)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if v != "Hello Redis" {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
bitKey := "bit_key"
|
||||||
|
if n, err := ledis.Int(c.Do("setbit", bitKey, 7, 1)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 0 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("getbit", bitKey, 7)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bitcount", bitKey)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 1 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bitpos", bitKey, 1)); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 7 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Do("set", "key1", "foobar")
|
||||||
|
c.Do("set", "key2", "abcdef")
|
||||||
|
|
||||||
|
if n, err := ledis.Int(c.Do("bitop", "and", "bit_dest_key", "key1", "key2")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if n != 6 {
|
||||||
|
t.Fatal(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
if v, err := ledis.String(c.Do("get", "bit_dest_key")); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
} else if v != "`bc`ab" {
|
||||||
|
t.Fatal(v)
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestKVM(t *testing.T) {
|
func TestKVM(t *testing.T) {
|
||||||
|
|
|
@ -13,7 +13,7 @@ func now() int64 {
|
||||||
|
|
||||||
func TestExpire(t *testing.T) {
|
func TestExpire(t *testing.T) {
|
||||||
// test for kv, list, hash, set, zset, bitmap in all
|
// test for kv, list, hash, set, zset, bitmap in all
|
||||||
ttlType := []string{"k", "l", "h", "s", "z", "b"}
|
ttlType := []string{"k", "l", "h", "s", "z"}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
expire string
|
expire string
|
||||||
|
@ -61,7 +61,6 @@ func TestExpire(t *testing.T) {
|
||||||
key = "bitmap_ttl"
|
key = "bitmap_ttl"
|
||||||
c.Do("bsetbit", key, 0, 1)
|
c.Do("bsetbit", key, 0, 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// expire + ttl
|
// expire + ttl
|
||||||
exp := int64(10)
|
exp := int64(10)
|
||||||
if n, err := ledis.Int(c.Do(expire, key, exp)); err != nil {
|
if n, err := ledis.Int(c.Do(expire, key, exp)); err != nil {
|
||||||
|
|
|
@ -33,7 +33,6 @@ func TestScan(t *testing.T) {
|
||||||
testListScan(t, c)
|
testListScan(t, c)
|
||||||
testZSetScan(t, c)
|
testZSetScan(t, c)
|
||||||
testSetScan(t, c)
|
testSetScan(t, c)
|
||||||
testBitScan(t, c)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,14 +153,3 @@ func testSetScan(t *testing.T, c *ledis.Client) {
|
||||||
checkScan(t, c, "xsscan")
|
checkScan(t, c, "xsscan")
|
||||||
checkRevScan(t, c, "xsrevscan")
|
checkRevScan(t, c, "xsrevscan")
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBitScan(t *testing.T, c *ledis.Client) {
|
|
||||||
for i := 0; i < 10; i++ {
|
|
||||||
if _, err := c.Do("bsetbit", fmt.Sprintf("%d", i), 1024, 1); err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
checkScan(t, c, "xbscan")
|
|
||||||
checkRevScan(t, c, "xbrevscan")
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue