Commit 55f5a80c authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent 3df8a3a8
...@@ -61,7 +61,10 @@ func fsIndexNew() *fsIndex { ...@@ -61,7 +61,10 @@ func fsIndexNew() *fsIndex {
// oid[6:8]oid[6:8]oid[6:8]...pos[0:6]pos[0:6]pos[0:6]... // oid[6:8]oid[6:8]oid[6:8]...pos[0:6]pos[0:6]pos[0:6]...
const oidPrefixMask zodb.Oid = ((1<<64-1) ^ (1<<16 -1)) // 0xffffffffffff0000 const (
oidPrefixMask zodb.Oid = (1<<64-1) ^ (1<<16 - 1) // 0xffffffffffff0000
posInvalidMask uint64 = (1<<64-1) ^ (1<<48 - 1) // 0xffff000000000000
)
// IndexSaveError is the error type returned by index save routines // IndexSaveError is the error type returned by index save routines
type IndexSaveError struct { type IndexSaveError struct {
...@@ -72,7 +75,7 @@ func (e *IndexSaveError) Error() string { ...@@ -72,7 +75,7 @@ func (e *IndexSaveError) Error() string {
return "index save: " + e.Err.Error() return "index save: " + e.Err.Error()
} }
// Save saves the index to a writer // Save saves index to a writer
func (fsi *fsIndex) Save(topPos int64, w io.Writer) error { func (fsi *fsIndex) Save(topPos int64, w io.Writer) error {
var err error var err error
...@@ -91,17 +94,16 @@ func (fsi *fsIndex) Save(topPos int64, w io.Writer) error { ...@@ -91,17 +94,16 @@ func (fsi *fsIndex) Save(topPos int64, w io.Writer) error {
posBuf := []byte{} // current pos[0:6]pos[0:6]... posBuf := []byte{} // current pos[0:6]pos[0:6]...
var t [2]interface{} // tuple for (oid, fsBucket.toString()) var t [2]interface{} // tuple for (oid, fsBucket.toString())
e, err := fsi.SeekFirst() e, _ := fsi.SeekFirst()
if err == io.EOF { // always only io.EOF indicating an empty btree if e != nil {
goto skip defer e.Close()
}
for { for {
oid, pos, errStop := e.Next() oid, pos, errStop := e.Next()
oidPrefix := oid & oidPrefixMask oidPrefix := oid & oidPrefixMask
if oidPrefix != oidPrefixCur || errStop != nil { if oidPrefix != oidPrefixCur || errStop != nil {
// emit (oid[:6], oid[6:8]oid[6:8]...pos[0:6]pos[0:6]...) // emit (oid[0:6], oid[6:8]oid[6:8]...pos[0:6]pos[0:6]...)
binary.BigEndian.PutUint64(oidb[:], uint64(oid)) binary.BigEndian.PutUint64(oidb[:], uint64(oid))
t[0] = oidb[0:6] t[0] = oidb[0:6]
t[1] = bytes.Join([][]byte{oidBuf, posBuf}, nil) t[1] = bytes.Join([][]byte{oidBuf, posBuf}, nil)
...@@ -119,17 +121,20 @@ func (fsi *fsIndex) Save(topPos int64, w io.Writer) error { ...@@ -119,17 +121,20 @@ func (fsi *fsIndex) Save(topPos int64, w io.Writer) error {
break break
} }
// check pos does not overflow 6 bytes
if uint64(pos) & posInvalidMask != 0 {
err = fmt.Errorf("entry position too large: 0x%x", pos)
goto out
}
binary.BigEndian.PutUint64(oidb[:], uint64(oid)) binary.BigEndian.PutUint64(oidb[:], uint64(oid))
binary.BigEndian.PutUint64(posb[:], uint64(pos)) binary.BigEndian.PutUint64(posb[:], uint64(pos))
// XXX check pos does not overflow 6 bytes
oidBuf = append(oidBuf, oidb[6:8]...) oidBuf = append(oidBuf, oidb[6:8]...)
posBuf = append(posBuf, posb[0:6]...) posBuf = append(posBuf, posb[0:6]...)
} }
}
e.Close()
skip:
err = p.Encode(pickle.None{}) err = p.Encode(pickle.None{})
} }
......
...@@ -9,6 +9,7 @@ import ( ...@@ -9,6 +9,7 @@ import (
"testing" "testing"
"../../zodb" "../../zodb"
"./fsb"
) )
type indexEntry struct { type indexEntry struct {
...@@ -32,7 +33,7 @@ var indexTest1 = [...]indexEntry { ...@@ -32,7 +33,7 @@ var indexTest1 = [...]indexEntry {
{0xffffffffffffffff, 777}, {0xffffffffffffffff, 777},
{0xfffffffffffffff0, 888}, {0xfffffffffffffff0, 888},
{0x8000000000000000, 999}, {0x8000000000000000, 999},
{0xa000000000000000, 0x7fffffffffffffff}, {0xa000000000000000, 0x0000ffffffffffff},
} }
func setIndex(fsi *fsIndex, kv []indexEntry) { func setIndex(fsi *fsIndex, kv []indexEntry) {
...@@ -41,6 +42,39 @@ func setIndex(fsi *fsIndex, kv []indexEntry) { ...@@ -41,6 +42,39 @@ func setIndex(fsi *fsIndex, kv []indexEntry) {
} }
} }
// test whether two trees are equal
func treeEqual(a, b *fsb.Tree) bool {
if a.Len() != b.Len() {
return false
}
ea, _ := a.SeekFirst()
eb, _ := b.SeekFirst()
if ea == nil {
// this means len(a) == 0 -> len(b) == 0 -> eb = nil
return true
}
for {
ka, va, stopa := ea.Next()
kb, vb, stopb := eb.Next()
if stopa != nil || stopb != nil {
if stopa != stopb {
panic("same-length trees iteration did not end at the same time")
}
break
}
if !(ka == kb && va == vb) {
return false
}
}
return true
}
func TestIndexLookup(t *testing.T) { func TestIndexLookup(t *testing.T) {
// the lookup is tested in cznic.b itself // the lookup is tested in cznic.b itself
// here we only lightly exercise it // here we only lightly exercise it
...@@ -125,5 +159,12 @@ func TestIndexSaveLoad(t *testing.T) { ...@@ -125,5 +159,12 @@ func TestIndexSaveLoad(t *testing.T) {
t.Errorf("index load: topPos mismatch: %v ; want %v", topPos2, topPos) t.Errorf("index load: topPos mismatch: %v ; want %v", topPos2, topPos)
} }
_ = fsi2 // XXX is it ok to compare trees via reflect.DeepEqual ?
if !treeEqual(fsi2.Tree, fsi.Tree) {
t.Errorf("index load: trees mismatch: %v ; want %v", fsi2.Tree, fsi.Tree)
}
// TODO check with
// {0xb000000000000000, 0x7fffffffffffffff}, // will cause 'entry position too large'
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment