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

View File

@ -17,7 +17,21 @@ func cmpBytes(a []byte, b []byte) bool {
return false 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) { func TestBinary(t *testing.T) {
//testSimple(t)
testSimpleII(t)
}
func testSimple(t *testing.T) {
db := getTestDB() db := getTestDB()
key := []byte("test_bin") key := []byte("test_bin")
@ -55,4 +69,42 @@ func TestBinary(t *testing.T) {
if cmpBytes(data, []byte{0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00}) { if cmpBytes(data, []byte{0x80, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00}) {
t.Error(data) 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))
}
} }