fix problem of size calculation in bin type, and add 'btail' api

This commit is contained in:
silentsai 2014-06-24 12:00:41 +08:00
parent 5be09d5836
commit 8c3ac7ebfb
2 changed files with 97 additions and 22 deletions

View File

@ -14,8 +14,13 @@ const (
)
const (
segWidth uint32 = 9
segSize uint32 = uint32(1 << segWidth) // byte
// byte
segByteWidth uint32 = 9
segByteSize uint32 = 1 << segByteWidth
// bit
segBitWidth uint32 = segByteWidth + 3
segBitSize uint32 = segByteSize << 3
minSeq uint32 = 0
maxSeq uint32 = uint32((1 << 31) - 1)
@ -69,6 +74,7 @@ func (db *DB) bEncodeBinKey(key []byte, seq uint32) []byte {
bk[pos] = db.index
pos++
bk[pos] = binType
pos++
binary.BigEndian.PutUint16(bk[pos:], uint16(len(key)))
pos += 2
@ -94,17 +100,26 @@ func (db *DB) bDecodeBinKey(bkey []byte) (key []byte, seq uint32, err error) {
}
key = bkey[4 : 4+keyLen]
seq = uint32(binary.BigEndian.Uint16(bkey[4+keyLen:]))
seq = uint32(binary.BigEndian.Uint32(bkey[4+keyLen:]))
return
}
func (db *DB) bCapByteSize(seq uint32, off uint32) uint32 {
var offByteSize uint32 = (off >> 3) + 1
if offByteSize > segByteSize {
offByteSize = segByteSize
}
return seq<<segByteWidth + offByteSize
}
func (db *DB) bParseOffset(key []byte, offset int32) (seq uint32, off uint32, err error) {
if offset < 0 {
if tailSeq, tailOff, e := db.bGetMeta(key); e != nil {
err = e
return
} else {
offset += int32(tailSeq<<segWidth | tailOff)
offset += int32(tailSeq<<segBitWidth | tailOff)
if offset < 0 {
err = errOffset
return
@ -114,8 +129,8 @@ func (db *DB) bParseOffset(key []byte, offset int32) (seq uint32, off uint32, er
off = uint32(offset)
seq = off >> segWidth
off &= (segSize - 1)
seq = off >> segBitWidth
off &= (segBitSize - 1)
return
}
@ -177,25 +192,27 @@ func (db *DB) BGet(key []byte) (data []byte, err error) {
return
}
var offByteLen uint32 = tailOff >> 3
if tailOff&7 > 0 {
offByteLen++
}
var dataCap uint32 = tailSeq<<3 + offByteLen
data = make([]byte, dataCap)
var capByteSize uint32 = db.bCapByteSize(tailSeq, tailOff)
data = make([]byte, capByteSize, capByteSize)
minKey := db.bEncodeBinKey(key, minSeq)
maxKey := db.bEncodeBinKey(key, tailSeq)
it := db.db.RangeLimitIterator(minKey, maxKey, leveldb.RangeClose, 0, -1)
for pos, end := uint32(0), uint32(0); it.Valid(); it.Next() {
end = pos + segSize
if end >= offByteLen {
end = offByteLen
var seq, s, e uint32
for ; it.Valid(); it.Next() {
if _, seq, err = db.bDecodeBinKey(it.Key()); err != nil {
data = nil
break
}
copy(data[pos:end], it.Value())
pos = end
s = seq << segByteWidth
e = s + segByteSize
if e > capByteSize {
e = capByteSize
}
copy(data[s:e], it.Value())
}
it.Close()
@ -218,7 +235,7 @@ func (db *DB) getSegment(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)
if err == nil && segment == nil {
segment = make([]byte, segSize, segSize) // can be optimize ?
segment = make([]byte, segByteSize, segByteSize) // can be optimize ?
}
return bk, segment, err
}
@ -307,9 +324,15 @@ func (db *DB) BCount(key []byte, start int32, end int32) (cnt int32, err error)
return
}
// func (db *DB) BLen(key []) (uint32, error) {
func (db *DB) BTail(key []byte) (uint32, error) {
// effective length of data, the highest bit-pos set in history
tailSeq, tailOff, err := db.bGetMeta(key)
if err != nil {
return 0, err
}
// }
return tailSeq<<segBitWidth | tailOff, nil
}
// func (db *DB) BOperation(op byte, dstkey []byte, srckeys ...[]byte) (int32, error) {
// // return :

View File

@ -17,7 +17,21 @@ func cmpBytes(a []byte, b []byte) bool {
return false
}
func newBytes(bitLen int32) []byte {
bytes := bitLen / 8
if bitLen%8 > 0 {
bytes++
}
return make([]byte, bytes, bytes)
}
func TestBinary(t *testing.T) {
//testSimple(t)
testSimpleII(t)
}
func testSimple(t *testing.T) {
db := getTestDB()
key := []byte("test_bin")
@ -55,4 +69,42 @@ func TestBinary(t *testing.T) {
if cmpBytes(data, []byte{0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00}) {
t.Error(data)
}
if tail, _ := db.BTail(key); tail != uint32(50) {
t.Error(tail)
}
}
func testSimpleII(t *testing.T) {
db := getTestDB()
key := []byte("test_bin")
pos := int32(1234567)
if ori, _ := db.BSetBit(key, pos, 1); ori != 0 {
t.Error(ori)
}
if v, _ := db.BGetBit(key, pos); v != 1 {
t.Error(v)
}
if v, _ := db.BGetBit(key, pos-1); v != 0 {
t.Error(v)
}
if v, _ := db.BGetBit(key, pos+1); v != 0 {
t.Error(v)
}
if tail, _ := db.BTail(key); tail != uint32(pos) {
t.Error(tail)
}
data, _ := db.BGet(key)
stdData := newBytes(pos + 1)
stdData[pos/8] = uint8(1 << (uint(pos) % 8))
if cmpBytes(data, stdData) {
t.Error(len(data))
}
}