offer function 'xor' 'not' in bit operation

This commit is contained in:
silentsai 2014-06-30 18:00:14 +08:00
parent cd194dff48
commit 70018092fe
2 changed files with 180 additions and 48 deletions

View File

@ -42,6 +42,10 @@ var bitsInByte = [256]int32{0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3,
6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 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} 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8}
var fillBits = [...]uint8{1, 3, 7, 15, 31, 63, 127, 255}
var emptySegment []byte = make([]byte, segByteSize, segByteSize)
var fillSegment []byte = func() []byte { var fillSegment []byte = func() []byte {
data := make([]byte, segByteSize, segByteSize) data := make([]byte, segByteSize, segByteSize)
for i := uint32(0); i < segByteSize; i++ { for i := uint32(0); i < segByteSize; i++ {
@ -216,7 +220,7 @@ func (db *DB) bDelete(t *tx, key []byte) (drop int64) {
it := db.db.RangeIterator(minKey, maxKey, leveldb.RangeClose) it := db.db.RangeIterator(minKey, maxKey, leveldb.RangeClose)
for ; it.Valid(); it.Next() { for ; it.Valid(); it.Next() {
t.Delete(it.Key()) t.Delete(it.Key())
drop = 1 drop++
} }
it.Close() it.Close()
@ -285,7 +289,7 @@ func (db *DB) getSegment(key []byte, seq uint32) ([]byte, []byte, error) {
func (db *DB) allocateSegment(key []byte, seq uint32) ([]byte, []byte, error) { func (db *DB) allocateSegment(key []byte, seq uint32) ([]byte, []byte, error) {
bk, segment, err := db.getSegment(key, seq) bk, segment, err := db.getSegment(key, seq)
if err == nil && segment == nil { if err == nil && segment == nil {
segment = make([]byte, segByteSize, segByteSize) // can be optimize ? segment = make([]byte, segByteSize, segByteSize)
} }
return bk, segment, err return bk, segment, err
} }
@ -389,6 +393,12 @@ func (db *DB) BTail(key []byte) (int32, error) {
return tail, nil return tail, nil
} }
func (db *DB) bIterator(key []byte) *leveldb.RangeLimitIterator {
sk := db.bEncodeBinKey(key, minSeq)
ek := db.bEncodeBinKey(key, maxSeq)
return db.db.RangeIterator(sk, ek, leveldb.RangeClose)
}
func (db *DB) bSegAnd(a []byte, b []byte, res *[]byte) { func (db *DB) bSegAnd(a []byte, b []byte, res *[]byte) {
if a == nil || b == nil { if a == nil || b == nil {
*res = nil *res = nil
@ -431,31 +441,60 @@ func (db *DB) bSegOr(a []byte, b []byte, res *[]byte) {
return return
} }
func (db *DB) bIterator(key []byte) *leveldb.RangeLimitIterator { func (db *DB) bSegXor(a []byte, b []byte, res *[]byte) {
sk := db.bEncodeBinKey(key, minSeq) if a == nil && b == nil {
ek := db.bEncodeBinKey(key, maxSeq) *res = fillSegment
return db.db.RangeIterator(sk, ek, leveldb.RangeClose) return
}
if a == nil {
a = emptySegment
}
if b == nil {
b = emptySegment
}
data := *res
if data == nil {
data = make([]byte, segByteSize, segByteSize)
*res = data
}
for i := uint32(0); i < segByteSize; i++ {
data[i] = a[i] ^ b[i]
}
return
} }
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) {
// return : // return :
// The size of the string stored in the destination key, // The size of the string stored in the destination key,
// that is equal to the size of the longest input string. // that is equal to the size of the longest input string.
blen = -1
var exeOp func([]byte, []byte, *[]byte) var exeOp func([]byte, []byte, *[]byte)
switch op { switch op {
case OPand: case OPand:
exeOp = db.bSegAnd exeOp = db.bSegAnd
case OPor: case OPor:
exeOp = db.bSegOr exeOp = db.bSegOr
case OPxor, OPnot:
exeOp = db.bSegXor
default: default:
return return
} }
if dstkey == nil || srckeys == nil || len(srckeys) == 0 { if dstkey == nil || srckeys == nil {
return return
} }
blen = -1 if (op == OPnot && len(srckeys) != 1) ||
(op != OPnot && len(srckeys) < 2) {
// msg("lack of arguments")
return
}
t := db.binTx t := db.binTx
t.Lock() t.Lock()
@ -466,9 +505,9 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
var nowSeq, nowOff int32 var nowSeq, nowOff int32
var keyNum int = len(srckeys) var keyNum int = len(srckeys)
var iniIdx int = 0 var srcIdx int = 0
for ; iniIdx < keyNum; iniIdx++ { for ; srcIdx < keyNum; srcIdx++ {
if nowSeq, nowOff, err = db.bGetMeta(srckeys[iniIdx]); err != nil { // todo : if key not exists .... if nowSeq, nowOff, err = db.bGetMeta(srckeys[srcIdx]); err != nil { // todo : if key not exists ....
return return
} }
@ -479,8 +518,8 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
} }
} }
if iniIdx+1 >= keyNum { // todo ... while operation is 'not' if srcIdx == keyNum {
// msg("lack of arguments") // none existing src key
return return
} }
@ -488,19 +527,38 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
var seq, off uint32 var seq, off uint32
var segments = make([][]byte, maxSegCount) // todo : init count also can be optimize while 'and' / 'or' var segments = make([][]byte, maxSegCount) // todo : init count also can be optimize while 'and' / 'or'
it := db.bIterator(srckeys[iniIdx]) if op == OPnot {
for ; it.Valid(); it.Next() { for i := uint32(0); i < maxDstSeq; i++ {
if _, seq, err = db.bDecodeBinKey(it.Key()); err != nil { segments[i] = fillSegment
// to do ...
it.Close()
return
} }
segments[seq] = it.Value()
var tailSeg = make([]byte, segByteSize, segByteSize)
var fillByte = fillBits[7]
var cnt = db.bCapByteSize(uint32(0), maxDstOff)
for i := uint32(0); i < cnt-1; i++ {
tailSeg[i] = fillByte
}
tailSeg[cnt-1] = fillBits[maxDstOff-(cnt-1)<<3]
segments[maxDstSeq] = tailSeg
} else {
it := db.bIterator(srckeys[srcIdx])
for ; it.Valid(); it.Next() {
if _, seq, err = db.bDecodeBinKey(it.Key()); err != nil {
// to do ...
it.Close()
return
}
segments[seq] = it.Value()
}
it.Close()
srcIdx++
} }
it.Close()
// operation with following keys // operation with following keys
for i := iniIdx + 1; i < keyNum; i++ { var res []byte
for i := srcIdx; i < keyNum; i++ {
if nowSeq, nowOff, err = db.bGetMeta(srckeys[i]); err != nil { if nowSeq, nowOff, err = db.bGetMeta(srckeys[i]); err != nil {
return return
} }
@ -516,10 +574,8 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
} }
} }
it = db.bIterator(srckeys[i]) it := db.bIterator(srckeys[i])
segIdx := uint32(0) for idx, end := uint32(0), false; !end; it.Next() {
for end := false; !end; it.Next() {
end = !it.Valid() end = !it.Valid()
if !end { if !end {
if _, seq, err = db.bDecodeBinKey(it.Key()); err != nil { if _, seq, err = db.bDecodeBinKey(it.Key()); err != nil {
@ -535,18 +591,17 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
// operation 'and' can be optimize here : // operation 'and' can be optimize here :
// if seq > max_segments_idx, this loop can be break, // if seq > max_segments_idx, this loop can be break,
// which can avoid cost from Key() and decode key // which can avoid cost from Key() and decode key
for ; idx < seq; idx++ {
if op == OPand || op == OPor { res = nil
for ; segIdx < seq; segIdx++ { exeOp(segments[idx], nil, &res)
if segments[segIdx] != nil { segments[idx] = res
exeOp(segments[segIdx], nil, &segments[segIdx]) }
}
}
} // else {...}
if !end { if !end {
exeOp(segments[seq], it.Value(), &segments[segIdx]) res = it.Value()
segIdx++ exeOp(segments[seq], res, &res)
segments[seq] = res
idx++
} }
} }
it.Close() it.Close()
@ -557,19 +612,15 @@ func (db *DB) BOperation(op uint8, dstkey []byte, srckeys ...[]byte) (blen int32
db.rmExpire(t, bExpType, dstkey) db.rmExpire(t, bExpType, dstkey)
// set data and meta // set data and meta
// if op == OPand || op == OPor {
// for i := maxDstSeq; i >= 0; i-- {
//
// }
// }
db.bSetMeta(t, dstkey, maxDstSeq, maxDstOff) db.bSetMeta(t, dstkey, maxDstSeq, maxDstOff)
// set data
var bk []byte var bk []byte
for seq, seg := range segments { for seq, seg := range segments {
if seg != nil { if seg != nil {
// todo: // todo:
// here can be optimize, like 'updateBinKeySeq', // here can be optimize, like 'updateBinKeySeq',
// avoid too many make mem // avoid allocate too many mem
bk = db.bEncodeBinKey(dstkey, uint32(seq)) bk = db.bEncodeBinKey(dstkey, uint32(seq))
t.Put(bk, seg) t.Put(bk, seg)
} }

View File

@ -6,11 +6,18 @@ import (
func cmpBytes(a []byte, b []byte) bool { func cmpBytes(a []byte, b []byte) bool {
if len(a) != len(b) { if len(a) != len(b) {
println("len diff")
println(len(a))
println(len(b))
return true return true
} }
for i, n := range a { for i, n := range a {
if n != b[i] { if n != b[i] {
println("diff !")
println(i)
println(n)
println(b[i])
return true return true
} }
} }
@ -27,9 +34,11 @@ func newBytes(bitLen int32) []byte {
} }
func TestBinary(t *testing.T) { func TestBinary(t *testing.T) {
testSimple(t) // testSimple(t)
testSimpleII(t) // testSimpleII(t)
testOp(t) // testOpAndOr(t)
// testOpXor(t)
testOpNot(t)
} }
func testSimple(t *testing.T) { func testSimple(t *testing.T) {
@ -80,7 +89,7 @@ func testSimpleII(t *testing.T) {
db := getTestDB() db := getTestDB()
db.FlushAll() db.FlushAll()
key := []byte("test_bin") key := []byte("test_bin_2")
pos := int32(1234567) pos := int32(1234567)
if ori, _ := db.BSetBit(key, pos, 1); ori != 0 { if ori, _ := db.BSetBit(key, pos, 1); ori != 0 {
@ -120,11 +129,11 @@ func testSimpleII(t *testing.T) {
} }
} }
func testOp(t *testing.T) { func testOpAndOr(t *testing.T) {
db := getTestDB() db := getTestDB()
db.FlushAll() db.FlushAll()
dstKey := []byte("test_bin_op") dstKey := []byte("test_bin_op_and_or")
k0 := []byte("op_0") k0 := []byte("op_0")
k1 := []byte("op_01") k1 := []byte("op_01")
@ -245,3 +254,75 @@ func testOp(t *testing.T) {
} }
} }
func testOpXor(t *testing.T) {
db := getTestDB()
db.FlushAll()
dstKey := []byte("test_bin_op_xor")
k0 := []byte("op_2_00")
k1 := []byte("op_2_01")
srcKeys := [][]byte{k0, k1}
db.BSetBit(k0, int32(0), 1)
db.BSetBit(k0, int32(7), 1)
db.BSetBit(k0, int32(segBitSize-1), 1)
db.BSetBit(k0, int32(segBitSize-8), 1)
db.BSetBit(k1, int32(7), 1)
db.BSetBit(k1, int32(segBitSize-8), 1)
var stdData []byte
var data []byte
// op - xor
db.BOperation(OPxor, dstKey, srcKeys...)
stdData = make([]byte, segByteSize)
stdData[0] = uint8(0x01)
stdData[segByteSize-1] = uint8(0x80)
data, _ = db.BGet(dstKey)
if cmpBytes(data, stdData) {
t.Fatal(false)
}
}
func testOpNot(t *testing.T) {
db := getTestDB()
db.FlushAll()
// intputs
dstKey := []byte("test_bin_op_xor")
k0 := []byte("op_not_0")
srcKeys := [][]byte{k0}
db.BSetBit(k0, int32(0), 1)
db.BSetBit(k0, int32(7), 1)
pos := segBitSize
for i := uint32(8); i >= 1; i -= 2 {
db.BSetBit(k0, int32(pos-i), 1)
}
db.BSetBit(k0, int32(3*segBitSize-10), 1)
// std
stdData := make([]byte, segByteSize*3-1)
for i, _ := range stdData {
stdData[i] = 255
}
stdData[0] = uint8(0x7e)
stdData[segByteSize-1] = uint8(0xaa)
stdData[segByteSize*3-2] = uint8(0x3f)
// op - not
db.BOperation(OPnot, dstKey, srcKeys...)
data, _ := db.BGet(dstKey)
if cmpBytes(data, stdData) {
t.Fatal(false)
}
}