mirror of https://github.com/ledisdb/ledisdb.git
problem of incorrect bit count within specified pos range is solved; corret itoperation return value
This commit is contained in:
parent
8f0b86b572
commit
3da485602b
106
ledis/t_bit.go
106
ledis/t_bit.go
|
@ -371,6 +371,65 @@ func (db *DB) bExpireAt(key []byte, when int64) (int64, error) {
|
||||||
return 1, nil
|
return 1, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db *DB) bCountByte(val byte, soff uint32, eoff uint32) int32 {
|
||||||
|
if soff > eoff {
|
||||||
|
soff, eoff = eoff, soff
|
||||||
|
}
|
||||||
|
|
||||||
|
mask := uint8(0)
|
||||||
|
if soff > 0 {
|
||||||
|
mask |= fillBits[soff-1]
|
||||||
|
}
|
||||||
|
if eoff < 7 {
|
||||||
|
mask |= (fillBits[7] ^ fillBits[eoff])
|
||||||
|
}
|
||||||
|
mask = fillBits[7] ^ mask
|
||||||
|
|
||||||
|
return bitsInByte[val&mask]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (db *DB) bCountSeg(key []byte, seq uint32, soff uint32, eoff uint32) (cnt int32, err error) {
|
||||||
|
if soff >= segBitSize || soff < 0 ||
|
||||||
|
eoff >= segBitSize || eoff < 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var segment []byte
|
||||||
|
if _, segment, err = db.bGetSegment(key, seq); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if segment == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if soff > eoff {
|
||||||
|
soff, eoff = eoff, soff
|
||||||
|
}
|
||||||
|
|
||||||
|
headIdx := int(soff >> 3)
|
||||||
|
endIdx := int(eoff >> 3)
|
||||||
|
sByteOff := soff - ((soff >> 3) << 3)
|
||||||
|
eByteOff := eoff - ((eoff >> 3) << 3)
|
||||||
|
|
||||||
|
if headIdx == endIdx {
|
||||||
|
cnt = db.bCountByte(segment[headIdx], sByteOff, eByteOff)
|
||||||
|
} else {
|
||||||
|
cnt = db.bCountByte(segment[headIdx], sByteOff, 7) +
|
||||||
|
db.bCountByte(segment[endIdx], 0, eByteOff)
|
||||||
|
}
|
||||||
|
|
||||||
|
// sum up following bytes
|
||||||
|
for idx, end := headIdx+1, endIdx-1; idx <= end; idx += 1 {
|
||||||
|
cnt += bitsInByte[segment[idx]]
|
||||||
|
if idx == end {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (db *DB) BGet(key []byte) (data []byte, err error) {
|
func (db *DB) BGet(key []byte) (data []byte, err error) {
|
||||||
if err = checkKeySize(key); err != nil {
|
if err = checkKeySize(key); err != nil {
|
||||||
return
|
return
|
||||||
|
@ -561,25 +620,53 @@ 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) {
|
||||||
var sseq uint32
|
var sseq, soff uint32
|
||||||
if sseq, _, err = db.bParseOffset(key, start); err != nil {
|
if sseq, soff, err = db.bParseOffset(key, start); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var eseq uint32
|
var eseq, eoff uint32
|
||||||
if eseq, _, err = db.bParseOffset(key, end); err != nil {
|
if eseq, eoff, err = db.bParseOffset(key, end); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if sseq > eseq || (sseq == eseq && soff > eoff) {
|
||||||
|
sseq, eseq = eseq, sseq
|
||||||
|
soff, eoff = eoff, soff
|
||||||
|
}
|
||||||
|
|
||||||
|
var segCnt int32
|
||||||
|
if eseq == sseq {
|
||||||
|
if segCnt, err = db.bCountSeg(key, sseq, soff, eoff); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
cnt = segCnt
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if segCnt, err = db.bCountSeg(key, sseq, soff, segBitSize-1); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
cnt += segCnt
|
||||||
|
}
|
||||||
|
|
||||||
|
if segCnt, err = db.bCountSeg(key, eseq, 0, eoff); err != nil {
|
||||||
|
return 0, err
|
||||||
|
} else {
|
||||||
|
cnt += segCnt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// middle segs
|
||||||
var segment []byte
|
var segment []byte
|
||||||
skey := db.bEncodeBinKey(key, sseq)
|
skey := db.bEncodeBinKey(key, sseq)
|
||||||
ekey := db.bEncodeBinKey(key, eseq)
|
ekey := db.bEncodeBinKey(key, eseq)
|
||||||
|
|
||||||
it := db.db.RangeIterator(skey, ekey, leveldb.RangeClose)
|
it := db.db.RangeIterator(skey, ekey, leveldb.RangeOpen)
|
||||||
for ; it.Valid(); it.Next() {
|
for ; it.Valid(); it.Next() {
|
||||||
segment = it.Value()
|
segment = it.Value()
|
||||||
for _, bit := range segment {
|
for _, bt := range segment {
|
||||||
cnt += bitsInByte[bit]
|
cnt += bitsInByte[bt]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it.Close()
|
it.Close()
|
||||||
|
@ -604,7 +691,7 @@ 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) {
|
||||||
// blen -
|
// blen -
|
||||||
// the size of the string stored in the 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.
|
||||||
|
|
||||||
var exeOp func([]byte, []byte, *[]byte)
|
var exeOp func([]byte, []byte, *[]byte)
|
||||||
|
@ -759,7 +846,8 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
|
||||||
|
|
||||||
err = t.Commit()
|
err = t.Commit()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
blen = int32(maxDstSeq<<segBitWidth | maxDstOff)
|
// blen = int32(db.bCapByteSize(maxDstOff, maxDstOff))
|
||||||
|
blen = int32(maxDstSeq<<segBitWidth | maxDstOff + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
|
@ -36,6 +36,7 @@ func newBytes(bitLen int32) []byte {
|
||||||
func TestBinary(t *testing.T) {
|
func TestBinary(t *testing.T) {
|
||||||
testSimple(t)
|
testSimple(t)
|
||||||
testSimpleII(t)
|
testSimpleII(t)
|
||||||
|
testCount(t)
|
||||||
testOpAndOr(t)
|
testOpAndOr(t)
|
||||||
testOpXor(t)
|
testOpXor(t)
|
||||||
testOpNot(t)
|
testOpNot(t)
|
||||||
|
@ -130,6 +131,68 @@ func testSimpleII(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testCount(t *testing.T) {
|
||||||
|
db := getTestDB()
|
||||||
|
db.FlushAll()
|
||||||
|
|
||||||
|
dstKey := []byte("test_bin_count")
|
||||||
|
|
||||||
|
if ori, _ := db.BSetBit(key, 0, 1); ori != 0 {
|
||||||
|
t.Error(ori)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ori, _ := db.BSetBit(key, 10, 1); ori != 0 {
|
||||||
|
t.Error(ori)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ori, _ := db.BSetBit(key, 262140, 1); ori != 0 {
|
||||||
|
t.Error(ori)
|
||||||
|
}
|
||||||
|
|
||||||
|
// count
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, -1); sum != 3 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 9); sum != 1 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 10); sum != 2 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 11); sum != 2 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 262139); sum != 2 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 262140); sum != 3 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 0, 262141); sum != 3 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 10, 262140); sum != 2 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 11, 262140); sum != 1 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
if sum, _ := db.BCount(key, 11, 262139); sum != 0 {
|
||||||
|
t.Error(sum)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func testOpAndOr(t *testing.T) {
|
func testOpAndOr(t *testing.T) {
|
||||||
db := getTestDB()
|
db := getTestDB()
|
||||||
db.FlushAll()
|
db.FlushAll()
|
||||||
|
|
Loading…
Reference in New Issue