diff --git a/ledis/t_bin.go b/ledis/t_bin.go index d435400..ef20aa4 100644 --- a/ledis/t_bin.go +++ b/ledis/t_bin.go @@ -4,6 +4,7 @@ import ( "encoding/binary" "errors" "github.com/siddontang/ledisdb/leveldb" + "sort" "time" ) @@ -19,6 +20,14 @@ type BitPair struct { Val uint8 } +type segBitInfo struct { + Seq uint32 + Off uint32 + Val uint8 +} + +type segBitInfoArray []segBitInfo + const ( // byte segByteWidth uint32 = 9 @@ -62,6 +71,7 @@ var fillSegment []byte = func() []byte { var errBinKey = errors.New("invalid bin key") var errOffset = errors.New("invalid offset") +var errDuplicatePos = errors.New("duplicate bit pos") func getBit(sz []byte, offset uint32) uint8 { index := offset >> 3 @@ -90,6 +100,22 @@ func setBit(sz []byte, offset uint32, val uint8) bool { return true } +func (datas *segBitInfoArray) Len() int { + return len(*datas) +} + +func (datas *segBitInfoArray) Less(i, j int) bool { + res := (*datas)[i].Seq < (*datas)[j].Seq + if !res && (*datas)[i].Seq == (*datas)[j].Seq { + res = (*datas)[i].Off < (*datas)[j].Off + } + return res +} + +func (datas *segBitInfoArray) Swap(i, j int) { + (*datas)[i], (*datas)[j] = (*datas)[j], (*datas)[i] +} + func (db *DB) bEncodeMetaKey(key []byte) []byte { mk := make([]byte, len(key)+2) mk[0] = db.index @@ -151,7 +177,7 @@ func (db *DB) bParseOffset(key []byte, offset int32) (seq uint32, off uint32, er err = e return } else if tailSeq >= 0 { - offset += int32(uint32(tailSeq)< 0 { + if _, _, err = db.bUpdateMeta(t, key, maxSeq, maxOff); err != nil { + return + } + + err = t.Commit() + } + + return +} func (db *DB) BGetBit(key []byte, offset int32) (uint8, error) { if seq, off, err := db.bParseOffset(key, offset); err != nil { diff --git a/ledis/t_bin_test.go b/ledis/t_bin_test.go index 137c6df..8782767 100644 --- a/ledis/t_bin_test.go +++ b/ledis/t_bin_test.go @@ -34,11 +34,12 @@ func newBytes(bitLen int32) []byte { } func TestBinary(t *testing.T) { - // testSimple(t) - // testSimpleII(t) - // testOpAndOr(t) - // testOpXor(t) + testSimple(t) + testSimpleII(t) + testOpAndOr(t) + testOpXor(t) testOpNot(t) + testMSetBit(t) } func testSimple(t *testing.T) { @@ -326,3 +327,53 @@ func testOpNot(t *testing.T) { t.Fatal(false) } } + +func testMSetBit(t *testing.T) { + db := getTestDB() + db.FlushAll() + + key := []byte("test_mset") + + var datas = make([]BitPair, 8) + + // 1st + datas[0] = BitPair{1000, 1} + datas[1] = BitPair{11, 1} + datas[2] = BitPair{10, 1} + datas[3] = BitPair{2, 1} + datas[4] = BitPair{int32(segBitSize - 1), 1} + datas[5] = BitPair{int32(segBitSize), 1} + datas[6] = BitPair{int32(segBitSize + 1), 1} + datas[7] = BitPair{int32(segBitSize) + 10, 0} + + db.BMSetBit(key, datas...) + + if sum, _ := db.BCount(key, 0, -1); sum != 7 { + t.Error(sum) + } + + if tail, _ := db.BTail(key); tail != int32(segBitSize+10) { + t.Error(tail) + } + + // 2nd + datas = make([]BitPair, 5) + + datas[0] = BitPair{1000, 0} + datas[1] = BitPair{int32(segBitSize + 1), 0} + datas[2] = BitPair{int32(segBitSize * 10), 1} + datas[3] = BitPair{10, 0} + datas[4] = BitPair{99, 0} + + db.BMSetBit(key, datas...) + + if sum, _ := db.BCount(key, 0, -1); sum != 7-3+1 { + t.Error(sum) + } + + if tail, _ := db.BTail(key); tail != int32(segBitSize*10) { + t.Error(tail) + } + + return +}