// Copyright (c) 2014, Suryandaru Triandana <syndtr@gmail.com>
|
|
// All rights reserved.
|
|
//
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
package table
|
|
|
|
import (
|
|
"bytes"
|
|
|
|
. "github.com/onsi/ginkgo"
|
|
. "github.com/onsi/gomega"
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/iterator"
|
|
"github.com/syndtr/goleveldb/leveldb/opt"
|
|
"github.com/syndtr/goleveldb/leveldb/storage"
|
|
"github.com/syndtr/goleveldb/leveldb/testutil"
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
|
)
|
|
|
|
type tableWrapper struct {
|
|
*Reader
|
|
}
|
|
|
|
func (t tableWrapper) TestFind(key []byte) (rkey, rvalue []byte, err error) {
|
|
return t.Reader.Find(key, false, nil)
|
|
}
|
|
|
|
func (t tableWrapper) TestGet(key []byte) (value []byte, err error) {
|
|
return t.Reader.Get(key, nil)
|
|
}
|
|
|
|
func (t tableWrapper) TestNewIterator(slice *util.Range) iterator.Iterator {
|
|
return t.Reader.NewIterator(slice, nil)
|
|
}
|
|
|
|
var _ = testutil.Defer(func() {
|
|
Describe("Table", func() {
|
|
Describe("approximate offset test", func() {
|
|
var (
|
|
buf = &bytes.Buffer{}
|
|
o = &opt.Options{
|
|
BlockSize: 1024,
|
|
Compression: opt.NoCompression,
|
|
}
|
|
)
|
|
|
|
// Building the table.
|
|
tw := NewWriter(buf, o)
|
|
tw.Append([]byte("k01"), []byte("hello"))
|
|
tw.Append([]byte("k02"), []byte("hello2"))
|
|
tw.Append([]byte("k03"), bytes.Repeat([]byte{'x'}, 10000))
|
|
tw.Append([]byte("k04"), bytes.Repeat([]byte{'x'}, 200000))
|
|
tw.Append([]byte("k05"), bytes.Repeat([]byte{'x'}, 300000))
|
|
tw.Append([]byte("k06"), []byte("hello3"))
|
|
tw.Append([]byte("k07"), bytes.Repeat([]byte{'x'}, 100000))
|
|
err := tw.Close()
|
|
|
|
It("Should be able to approximate offset of a key correctly", func() {
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
|
|
tr, err := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), storage.FileDesc{}, nil, nil, o)
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
CheckOffset := func(key string, expect, threshold int) {
|
|
offset, err := tr.OffsetOf([]byte(key))
|
|
Expect(err).ShouldNot(HaveOccurred())
|
|
Expect(offset).Should(BeNumerically("~", expect, threshold), "Offset of key %q", key)
|
|
}
|
|
|
|
CheckOffset("k0", 0, 0)
|
|
CheckOffset("k01a", 0, 0)
|
|
CheckOffset("k02", 0, 0)
|
|
CheckOffset("k03", 0, 0)
|
|
CheckOffset("k04", 10000, 1000)
|
|
CheckOffset("k04a", 210000, 1000)
|
|
CheckOffset("k05", 210000, 1000)
|
|
CheckOffset("k06", 510000, 1000)
|
|
CheckOffset("k07", 510000, 1000)
|
|
CheckOffset("xyz", 610000, 2000)
|
|
})
|
|
})
|
|
|
|
Describe("read test", func() {
|
|
Build := func(kv testutil.KeyValue) testutil.DB {
|
|
o := &opt.Options{
|
|
BlockSize: 512,
|
|
BlockRestartInterval: 3,
|
|
}
|
|
buf := &bytes.Buffer{}
|
|
|
|
// Building the table.
|
|
tw := NewWriter(buf, o)
|
|
kv.Iterate(func(i int, key, value []byte) {
|
|
tw.Append(key, value)
|
|
})
|
|
tw.Close()
|
|
|
|
// Opening the table.
|
|
tr, _ := NewReader(bytes.NewReader(buf.Bytes()), int64(buf.Len()), storage.FileDesc{}, nil, nil, o)
|
|
return tableWrapper{tr}
|
|
}
|
|
Test := func(kv *testutil.KeyValue, body func(r *Reader)) func() {
|
|
return func() {
|
|
db := Build(*kv)
|
|
if body != nil {
|
|
body(db.(tableWrapper).Reader)
|
|
}
|
|
testutil.KeyValueTesting(nil, *kv, db, nil, nil)
|
|
}
|
|
}
|
|
|
|
testutil.AllKeyValueTesting(nil, Build, nil, nil)
|
|
Describe("with one key per block", Test(testutil.KeyValue_Generate(nil, 9, 1, 1, 10, 512, 512), func(r *Reader) {
|
|
It("should have correct blocks number", func() {
|
|
indexBlock, err := r.readBlock(r.indexBH, true)
|
|
Expect(err).To(BeNil())
|
|
Expect(indexBlock.restartsLen).Should(Equal(9))
|
|
})
|
|
}))
|
|
})
|
|
})
|
|
})
|