0
0
bleve/index/store/test/isolation.go
2016-10-02 10:13:14 -04:00

192 lines
4.2 KiB
Go

// Copyright (c) 2014 Couchbase, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package test
import (
"fmt"
"reflect"
"testing"
"github.com/blevesearch/bleve/index/store"
)
// tests focused on verifying that readers are isolated from writers
func CommonTestReaderIsolation(t *testing.T, s store.KVStore) {
// insert a kv pair
writer, err := s.Writer()
if err != nil {
t.Error(err)
}
// **************************************************
// this is a hack only required for BoltDB
// however its harmless so to keep the tests
// the same everywhere, we include it here
//
// this is a hack to try to pre-emptively overflow
// boltdb writes *MAY* block a long reader
// in particular, if the write requires additional
// allocation, it must acquire the same lock as
// the reader, thus cannot continue until that
// reader is closed.
// in general this is not a problem for bleve
// (though it may affect performance in some cases)
// but it is a problem for this test which attempts
// to easily verify that readers are isolated
// this hack writes enough initial data such that
// the subsequent writes do not require additional
// space
hackSize := 1000
batch := writer.NewBatch()
for i := 0; i < hackSize; i++ {
k := fmt.Sprintf("x%d", i)
batch.Set([]byte(k), []byte("filler"))
}
err = writer.ExecuteBatch(batch)
if err != nil {
t.Fatal(err)
}
// **************************************************
batch = writer.NewBatch()
batch.Set([]byte("a"), []byte("val-a"))
err = writer.ExecuteBatch(batch)
if err != nil {
t.Fatal(err)
}
err = writer.Close()
if err != nil {
t.Fatal(err)
}
// create an isolated reader
reader, err := s.Reader()
if err != nil {
t.Error(err)
}
defer func() {
err := reader.Close()
if err != nil {
t.Fatal(err)
}
}()
// verify that we see the value already inserted
val, err := reader.Get([]byte("a"))
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(val, []byte("val-a")) {
t.Errorf("expected val-a, got nil")
}
// verify that an iterator sees it
count := 0
it := reader.RangeIterator([]byte{0}, []byte{'x'})
defer func() {
err := it.Close()
if err != nil {
t.Fatal(err)
}
}()
for it.Valid() {
it.Next()
count++
}
if count != 1 {
t.Errorf("expected iterator to see 1, saw %d", count)
}
// add something after the reader was created
writer, err = s.Writer()
if err != nil {
t.Error(err)
}
batch = writer.NewBatch()
batch.Set([]byte("b"), []byte("val-b"))
err = writer.ExecuteBatch(batch)
if err != nil {
t.Fatal(err)
}
err = writer.Close()
if err != nil {
t.Fatal(err)
}
// ensure that a newer reader sees it
newReader, err := s.Reader()
if err != nil {
t.Error(err)
}
defer func() {
err := newReader.Close()
if err != nil {
t.Fatal(err)
}
}()
val, err = newReader.Get([]byte("b"))
if err != nil {
t.Error(err)
}
if !reflect.DeepEqual(val, []byte("val-b")) {
t.Errorf("expected val-b, got nil")
}
// ensure that the direct iterator sees it
count = 0
it2 := newReader.RangeIterator([]byte{0}, []byte{'x'})
defer func() {
err := it2.Close()
if err != nil {
t.Fatal(err)
}
}()
for it2.Valid() {
it2.Next()
count++
}
if count != 2 {
t.Errorf("expected iterator to see 2, saw %d", count)
}
// but that the isolated reader does not
val, err = reader.Get([]byte("b"))
if err != nil {
t.Error(err)
}
if val != nil {
t.Errorf("expected nil, got %v", val)
}
// and ensure that the iterator on the isolated reader also does not
count = 0
it3 := reader.RangeIterator([]byte{0}, []byte{'x'})
defer func() {
err := it3.Close()
if err != nil {
t.Fatal(err)
}
}()
for it3.Valid() {
it3.Next()
count++
}
if count != 1 {
t.Errorf("expected iterator to see 1, saw %d", count)
}
}