add kv bit operation support

old bitmap type will be deprecated later
This commit is contained in:
siddontang 2015-02-05 15:37:17 +08:00
parent 1540f81e68
commit b94a604f7a
12 changed files with 1619 additions and 1046 deletions

View File

@ -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"
)

View File

@ -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]))
} // }
} }

View File

@ -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)
} }

File diff suppressed because it is too large Load Diff

View File

@ -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"
) )
@ -434,19 +437,7 @@ func (db *DB) SetRange(key []byte, offset int, value []byte) (int64, error) {
return int64(len(oldValue)), nil return int64(len(oldValue)), nil
} }
func (db *DB) GetRange(key []byte, start int, end int) ([]byte, error) { func getRange(start int, end int, valLen int) (int, int) {
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)
if start < 0 { if start < 0 {
start = valLen + start start = valLen + start
} }
@ -466,6 +457,23 @@ func (db *DB) GetRange(key []byte, start int, end int) ([]byte, error) {
if end >= valLen { if end >= valLen {
end = valLen - 1 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 { if start > end {
return nil, nil return nil, nil
@ -519,3 +527,245 @@ func (db *DB) Append(key []byte, value []byte) (int64, error) {
return int64(len(oldValue)), 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
}
}

View File

@ -98,6 +98,155 @@ func TestDBKV(t *testing.T) {
} else if n != 11 { } else if n != 11 {
t.Fatal(n) 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) {

View File

@ -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
} }

View File

@ -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)
} // }
} // }

View File

@ -467,13 +467,142 @@ func strlenCommand(c *client) error {
return nil 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("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("getrange", getrangeCommand)
register("getset", getsetCommand) register("getset", getsetCommand)
register("incr", incrCommand) register("incr", incrCommand)
@ -481,6 +610,7 @@ func init() {
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("setrange", setrangeCommand)

View File

@ -104,6 +104,46 @@ func TestKV(t *testing.T) {
t.Fatal(v) 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) {

View File

@ -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 {

View File

@ -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")
}