Skip to content

Commit

Permalink
Add Fetch API to typed fields (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
xichen2020 committed Jan 11, 2019
1 parent 1991c4e commit 138c65f
Show file tree
Hide file tree
Showing 73 changed files with 2,492 additions and 373 deletions.
1 change: 1 addition & 0 deletions .excludemetalint
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
vendor/
generated/
index/template/
values/template/
_mock.go
_gen.go
File renamed without changes.
6 changes: 6 additions & 0 deletions generated/generics/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@

// Iterator related template instantiations.

//go:generate sh -c "cat $GOPATH/src/$PACKAGE/index/template/at_position_value_field_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/index/field/at_position_bool_field_iterator.gen.go -pkg=field -imp \"github.com/xichen2020/eventdb/values/iterator\" gen \"GenericValue=bool ForwardValueIterator=BoolIterator:iterator.ForwardBoolIterator SeekableValueIterator=SeekableBoolIterator:iterator.SeekableBoolIterator atPositionValueFieldIterator=atPositionBoolFieldIterator newAtPositionValueFieldIterator=newAtPositionBoolFieldIterator errPositionIterValueIterCountMismatch=errPositionIterBoolIterCountMismatch\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/index/template/at_position_value_field_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/index/field/at_position_int_field_iterator.gen.go -pkg=field -imp \"github.com/xichen2020/eventdb/values/iterator\" gen \"GenericValue=int ForwardValueIterator=IntIterator:iterator.ForwardIntIterator SeekableValueIterator=SeekableIntIterator:iterator.SeekableIntIterator atPositionValueFieldIterator=atPositionIntFieldIterator newAtPositionValueFieldIterator=newAtPositionIntFieldIterator errPositionIterValueIterCountMismatch=errPositionIterIntIterCountMismatch\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/index/template/at_position_value_field_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/index/field/at_position_double_field_iterator.gen.go -pkg=field -imp \"github.com/xichen2020/eventdb/values/iterator\" gen \"GenericValue=float64 ForwardValueIterator=DoubleIterator:iterator.ForwardDoubleIterator SeekableValueIterator=SeekableDoubleIterator:iterator.SeekableDoubleIterator atPositionValueFieldIterator=atPositionDoubleFieldIterator newAtPositionValueFieldIterator=newAtPositionDoubleFieldIterator errPositionIterValueIterCountMismatch=errPositionIterDoubleIterCountMismatch\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/index/template/at_position_value_field_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/index/field/at_position_string_field_iterator.gen.go -pkg=field -imp \"github.com/xichen2020/eventdb/values/iterator\" gen \"GenericValue=string ForwardValueIterator=StringIterator:iterator.ForwardStringIterator SeekableValueIterator=SeekableStringIterator:iterator.SeekableStringIterator atPositionValueFieldIterator=atPositionStringFieldIterator newAtPositionValueFieldIterator=newAtPositionStringFieldIterator errPositionIterValueIterCountMismatch=errPositionIterStringIterCountMismatch\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/index/template/at_position_value_field_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/index/field/at_position_time_field_iterator.gen.go -pkg=field -imp \"github.com/xichen2020/eventdb/values/iterator\" gen \"GenericValue=int64 ForwardValueIterator=TimeIterator:iterator.ForwardTimeIterator SeekableValueIterator=SeekableTimeIterator:iterator.SeekableTimeIterator atPositionValueFieldIterator=atPositionTimeFieldIterator newAtPositionValueFieldIterator=newAtPositionTimeFieldIterator errPositionIterValueIterCountMismatch=errPositionIterTimeIterCountMismatch\""

//go:generate sh -c "cat $GOPATH/src/$PACKAGE/values/template/filtered_value_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/values/iterator/impl/filtered_bool_iterator.gen.go -pkg=impl -imp \"github.com/xichen2020/eventdb/values/iterator\" -imp \"github.com/xichen2020/eventdb/filter\" gen \"GenericValue=bool ForwardValueIterator=BoolIterator:iterator.ForwardBoolIterator FilteredValueIterator=FilteredBoolIterator ValueFilter=BoolFilter:filter.BoolFilter\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/values/template/filtered_value_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/values/iterator/impl/filtered_int_iterator.gen.go -pkg=impl -imp \"github.com/xichen2020/eventdb/values/iterator\" -imp \"github.com/xichen2020/eventdb/filter\" gen \"GenericValue=int ForwardValueIterator=IntIterator:iterator.ForwardIntIterator FilteredValueIterator=FilteredIntIterator ValueFilter=IntFilter:filter.IntFilter\""
//go:generate sh -c "cat $GOPATH/src/$PACKAGE/values/template/filtered_value_iterator.go | awk '/^package/{i++}i' | genny -out=$GOPATH/src/$PACKAGE/values/iterator/impl/filtered_double_iterator.gen.go -pkg=impl -imp \"github.com/xichen2020/eventdb/values/iterator\" -imp \"github.com/xichen2020/eventdb/filter\" gen \"GenericValue=float64 ForwardValueIterator=DoubleIterator:iterator.ForwardDoubleIterator FilteredValueIterator=FilteredDoubleIterator ValueFilter=DoubleFilter:filter.DoubleFilter\""
Expand Down
6 changes: 3 additions & 3 deletions generated/mocks/generate.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package mocks

// mockgen rules for generating mocks for exported interfaces (reflection mode).
//go:generate sh -c "mockgen -package=digest $PACKAGE/digest FdWithDigestWriter | genclean -pkg $PACKAGE/digest -out $GOPATH/src/$PACKAGE/digest/writer_mock.go"
//go:generate sh -c "mockgen -package=index $PACKAGE/index DocIDSetIterator | genclean -pkg $PACKAGE/index -out $GOPATH/src/$PACKAGE/index/document_mock.go"
//go:generate sh -c "mockgen -package=iterator $PACKAGE/values/iterator ForwardBoolIterator,ForwardIntIterator,ForwardDoubleIterator,ForwardStringIterator,ForwardTimeIterator,PositionIterator | genclean -pkg $PACKAGE/values/iterator -out $GOPATH/src/$PACKAGE/values/iterator/iterator_mock.go"
//go:generate sh -c "mockgen -package=digest $PACKAGE/digest FdWithDigestWriter | genclean -pkg $PACKAGE/digest -out $GOPATH/src/$PACKAGE/digest/digest_mock.go"
//go:generate sh -c "mockgen -package=index $PACKAGE/index DocIDSetIterator,SeekableDocIDSetIterator,DocIDPositionIterator | genclean -pkg $PACKAGE/index -out $GOPATH/src/$PACKAGE/index/index_mock.go"
//go:generate sh -c "mockgen -package=iterator $PACKAGE/values/iterator ForwardBoolIterator,ForwardIntIterator,ForwardDoubleIterator,ForwardStringIterator,ForwardTimeIterator,SeekableBoolIterator,SeekableIntIterator,SeekableDoubleIterator,SeekableStringIterator,SeekableTimeIterator,PositionIterator | genclean -pkg $PACKAGE/values/iterator -out $GOPATH/src/$PACKAGE/values/iterator/iterator_mock.go"
//go:generate sh -c "mockgen -package=values $PACKAGE/values BoolValues,IntValues,DoubleValues,StringValues,TimeValues | genclean -pkg $PACKAGE/values -out $GOPATH/src/$PACKAGE/values/values_mock.go"

// mockgen rules for generating mocks for unexported interfaces (file mode).
Expand Down
72 changes: 57 additions & 15 deletions index/at_position_doc_id_set_iterator.go
Original file line number Diff line number Diff line change
@@ -1,60 +1,102 @@
package index

import (
"errors"

"github.com/xichen2020/eventdb/values/iterator"
)

var (
errPositionIterDocIDIterCountMismatch = errors.New("doc ID iterator and the position iterator iterator count mismatch")
)

// AtPositionDocIDSetIterator outputs the doc IDs from the doc ID set iterator at the
// given positions from the position iterator.
type AtPositionDocIDSetIterator struct {
docIt DocIDSetIterator
positionIt iterator.PositionIterator
docIt DocIDSetIterator
seekableDocIt SeekableDocIDSetIterator
positionIt iterator.PositionIterator

done bool
err error
firstTime bool
currDocID int32
currPos int
done bool
}

// NewAtPositionDocIDSetIterator creates a new at position iterator.
func NewAtPositionDocIDSetIterator(
docIt DocIDSetIterator,
positionIt iterator.PositionIterator,
) *AtPositionDocIDSetIterator {
seekableDocIt, _ := docIt.(SeekableDocIDSetIterator)
if seekableDocIt != nil {
docIt = nil
}
return &AtPositionDocIDSetIterator{
docIt: docIt,
positionIt: positionIt,
docIt: docIt,
seekableDocIt: seekableDocIt,
positionIt: positionIt,
firstTime: true,
}
}

// Next returns true if there are more doc IDs to be iterated over.
func (it *AtPositionDocIDSetIterator) Next() bool {
if it.done {
if it.done || it.err != nil {
return false
}
if !it.positionIt.Next() {
it.done = true
return false
}
nextPos := it.positionIt.Current()
nextPos := it.positionIt.Position()
distance := nextPos - it.currPos
// TODO(xichen): Look into optimizations to speed this up if the doc ID set iterator
// supports a `Seek` or `Advance` API.
for i := 0; i < distance; i++ {
if !it.docIt.Next() {
panic("doc ID iterator and the position iterator iterator count mismatch")

// We have a next position, now advance the doc ID set iterator for the first time.
if it.firstTime {
it.firstTime = false
if hasNoValues :=
(it.seekableDocIt != nil && !it.seekableDocIt.Next()) ||
(it.docIt != nil && !it.docIt.Next()); hasNoValues {
it.err = errPositionIterDocIDIterCountMismatch
return false
}
}
it.currDocID = it.docIt.DocID()

if it.seekableDocIt != nil {
if it.err = it.seekableDocIt.SeekForward(distance); it.err != nil {
return false
}
it.currDocID = it.seekableDocIt.DocID()
} else {
for i := 0; i < distance; i++ {
if !it.docIt.Next() {
it.err = errPositionIterDocIDIterCountMismatch
return false
}
}
it.currDocID = it.docIt.DocID()
}
it.currPos = nextPos
return true
}

// DocID returns the current doc ID.
func (it *AtPositionDocIDSetIterator) DocID() int32 { return it.currDocID }

// Err returns any error encountered.
func (it *AtPositionDocIDSetIterator) Err() error { return it.err }

// Close closes the iterator.
func (it *AtPositionDocIDSetIterator) Close() {
it.docIt.Close()
it.docIt = nil
if it.docIt != nil {
it.docIt.Close()
it.docIt = nil
} else {
it.seekableDocIt.Close()
it.seekableDocIt = nil
}
it.positionIt = nil
it.err = nil
}
49 changes: 44 additions & 5 deletions index/at_position_doc_id_set_iterator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"github.com/stretchr/testify/require"
)

func TestAtPositionDocIDSetIterator(t *testing.T) {
func TestAtPositionDocIDSetIteratorForwardOnly(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

Expand All @@ -28,19 +28,58 @@ func TestAtPositionDocIDSetIterator(t *testing.T) {
mockPositionIt := iterator.NewMockPositionIterator(ctrl)
gomock.InOrder(
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Current().Return(2),
mockPositionIt.EXPECT().Position().Return(2),
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Current().Return(4),
mockPositionIt.EXPECT().Position().Return(4),
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Current().Return(7),
mockPositionIt.EXPECT().Position().Return(7),
mockPositionIt.EXPECT().Next().Return(false),
)
atPositionIt := NewAtPositionDocIDSetIterator(docIDSetIter, mockPositionIt)
defer atPositionIt.Close()

expected := []int32{5, 20, 90}
expected := []int32{7, 54, 107}
var actual []int32
for atPositionIt.Next() {
actual = append(actual, atPositionIt.DocID())
}
require.Equal(t, expected, actual)
}

func TestAtPositionDocIDSetIteratorSeekable(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

docIDSetIter := NewMockSeekableDocIDSetIterator(ctrl)
gomock.InOrder(
docIDSetIter.EXPECT().Next().Return(true),
docIDSetIter.EXPECT().SeekForward(2).Return(nil),
docIDSetIter.EXPECT().DocID().Return(int32(7)),
docIDSetIter.EXPECT().SeekForward(2).Return(nil),
docIDSetIter.EXPECT().DocID().Return(int32(54)),
docIDSetIter.EXPECT().SeekForward(3).Return(nil),
docIDSetIter.EXPECT().DocID().Return(int32(107)),
docIDSetIter.EXPECT().Close(),
)

mockPositionIt := iterator.NewMockPositionIterator(ctrl)
gomock.InOrder(
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Position().Return(2),
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Position().Return(4),
mockPositionIt.EXPECT().Next().Return(true),
mockPositionIt.EXPECT().Position().Return(7),
mockPositionIt.EXPECT().Next().Return(false),
)
atPositionIt := NewAtPositionDocIDSetIterator(docIDSetIter, mockPositionIt)
defer atPositionIt.Close()

expected := []int32{7, 54, 107}
var actual []int32
for atPositionIt.Next() {
actual = append(actual, atPositionIt.DocID())
}
require.NoError(t, atPositionIt.Err())
require.Equal(t, expected, actual)
}
55 changes: 55 additions & 0 deletions index/bitmap_based_doc_id_position_iterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package index

import "github.com/pilosa/pilosa/roaring"

type bitmapBasedDocIDPositionIterator struct {
bm *roaring.Bitmap
maskingIt DocIDSetIterator

done bool
currDocID int32
currPosition int
}

// nolint: deadcode
func newBitmapBasedDocIDPositionIterator(
bm *roaring.Bitmap,
maskingIt DocIDSetIterator,
) *bitmapBasedDocIDPositionIterator {
return &bitmapBasedDocIDPositionIterator{
bm: bm,
maskingIt: maskingIt,
currDocID: -1,
currPosition: -1,
}
}

func (it *bitmapBasedDocIDPositionIterator) Next() bool {
if it.done {
return false
}
if !it.maskingIt.Next() {
it.done = true
return false
}
currDocID := it.maskingIt.DocID()
if !it.bm.Contains(uint64(currDocID)) {
return it.Next()
}
// Find the number of bits set between [prevDocID+1, it.currDocID+1).
prevDocID := it.currDocID
it.currDocID = currDocID
numBitsSet := it.bm.CountRange(uint64(prevDocID+1), uint64(it.currDocID+1))
it.currPosition += int(numBitsSet)
return true
}

func (it *bitmapBasedDocIDPositionIterator) DocID() int32 { return it.currDocID }

func (it *bitmapBasedDocIDPositionIterator) Position() int { return it.currPosition }

func (it *bitmapBasedDocIDPositionIterator) Close() {
it.bm = nil
it.maskingIt.Close()
it.maskingIt = nil
}
57 changes: 57 additions & 0 deletions index/bitmap_based_doc_id_position_iterator_bench_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package index

import (
"testing"

"github.com/pilosa/pilosa/roaring"
)

// Summary: The default doc ID position iterator is as fast as the custom one, with
// fewer memory allocations.

func BenchmarkDefaultBitmapDocIDPositionIterator(b *testing.B) {
bm := initBenchBitmap(benchNumTotalDocs, 5)
ds := initBenchDocIDSet(benchNumTotalDocs, 8)

b.ResetTimer()
for i := 0; i < b.N; i++ {
bmIt := newBitmapBasedDocIDSet(bm).Iter()
dsIt := newArrayBasedDocIDSetIterator(ds)
defaultIt := NewDocIDPositionIterator(bmIt, dsIt)
count := 0
for defaultIt.Next() {
benchDocID = defaultIt.DocID()
benchPos = defaultIt.Position()
count++
}
}
}

func BenchmarkCustomBitmapDocIDPositionIterator(b *testing.B) {
bm := initBenchBitmap(benchNumTotalDocs, 5)
ds := initBenchDocIDSet(benchNumTotalDocs, 8)

bm.Optimize()
b.ResetTimer()
for i := 0; i < b.N; i++ {
dsIt := newArrayBasedDocIDSetIterator(ds)
it := newBitmapBasedDocIDPositionIterator(bm, dsIt)
count := 0
for it.Next() {
benchDocID = it.DocID()
benchPos = it.Position()
count++
}
}
}

// nolint: unparam
func initBenchBitmap(n int, everyN int) *roaring.Bitmap {
bm := roaring.NewBitmap()
for j := 0; j < n; j++ {
if j%everyN == 0 {
bm.DirectAdd(uint64(j))
}
}
return bm
}
41 changes: 41 additions & 0 deletions index/bitmap_based_doc_id_position_iterator_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package index

import (
"testing"

"github.com/golang/mock/gomock"
"github.com/pilosa/pilosa/roaring"
"github.com/stretchr/testify/require"
)

func TestBitmapBasedDocIDPositionIterator(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

bm := roaring.NewBitmap(0, 3, 5, 9, 12, 19, 23)

maskingIt := NewMockDocIDSetIterator(ctrl)
gomock.InOrder(
maskingIt.EXPECT().Next().Return(true),
maskingIt.EXPECT().DocID().Return(int32(0)).MinTimes(1),
maskingIt.EXPECT().Next().Return(true),
maskingIt.EXPECT().DocID().Return(int32(7)).MinTimes(1),
maskingIt.EXPECT().Next().Return(true),
maskingIt.EXPECT().DocID().Return(int32(12)).MinTimes(1),
maskingIt.EXPECT().Next().Return(false).AnyTimes(),
)

var (
docIDs []int32
positions []int
expectedDocIDs = []int32{0, 12}
expectedPositions = []int{0, 4}
)
it := newBitmapBasedDocIDPositionIterator(bm, maskingIt)
for it.Next() {
docIDs = append(docIDs, it.DocID())
positions = append(positions, it.Position())
}
require.Equal(t, expectedDocIDs, docIDs)
require.Equal(t, expectedPositions, positions)
}
Loading

0 comments on commit 138c65f

Please sign in to comment.