Skip to content

Commit dbbee60

Browse files
committed
Update index.Readable interface to support retreiving new doc.Document
1 parent 3a7e184 commit dbbee60

File tree

18 files changed

+505
-73
lines changed

18 files changed

+505
-73
lines changed

src/dbnode/storage/index/read_through_segment.go

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,13 +262,23 @@ func (s *readThroughSegmentReader) AllDocs() (index.IDDocIterator, error) {
262262
return s.reader.AllDocs()
263263
}
264264

265+
// Metadata is a pass through call, since there's no postings list to cache.
266+
func (s *readThroughSegmentReader) Metadata(id postings.ID) (doc.Metadata, error) {
267+
return s.reader.Metadata(id)
268+
}
269+
270+
// MetadataIterator is a pass through call, since there's no postings list to cache.
271+
func (s *readThroughSegmentReader) MetadataIterator(pl postings.List) (doc.MetadataIterator, error) {
272+
return s.reader.MetadataIterator(pl)
273+
}
274+
265275
// Doc is a pass through call, since there's no postings list to cache.
266-
func (s *readThroughSegmentReader) Doc(id postings.ID) (doc.Metadata, error) {
276+
func (s *readThroughSegmentReader) Doc(id postings.ID) (doc.Document, error) {
267277
return s.reader.Doc(id)
268278
}
269279

270280
// Docs is a pass through call, since there's no postings list to cache.
271-
func (s *readThroughSegmentReader) Docs(pl postings.List) (doc.MetadataIterator, error) {
281+
func (s *readThroughSegmentReader) Docs(pl postings.List) (doc.Iterator, error) {
272282
return s.reader.Docs(pl)
273283
}
274284

src/m3ninx/doc/types.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,23 @@ type MetadataIterator interface {
3939
// Close releases any internal resources used by the iterator.
4040
Close() error
4141
}
42+
43+
// Iterator provides an iterator over a collection of documents. It is NOT
44+
// safe for multiple goroutines to invoke methods on an Iterator simultaneously.
45+
type Iterator interface {
46+
// Next returns a bool indicating if the iterator has any more documents
47+
// to return.
48+
Next() bool
49+
50+
// Current returns the current document. It is only safe to call Current immediately
51+
// after a call to Next confirms there are more elements remaining. The Document
52+
// returned from Current is only valid until the following call to Next(). Callers
53+
// should copy the Document if they need it live longer.
54+
Current() Document
55+
56+
// Err returns any errors encountered during iteration.
57+
Err() error
58+
59+
// Close releases any internal resources used by the iterator.
60+
Close() error
61+
}

src/m3ninx/index/index_mock.go

Lines changed: 76 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/m3ninx/index/iterator.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// Copyright (c) 2021 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package index
22+
23+
import (
24+
"github.com/m3db/m3/src/m3ninx/doc"
25+
"github.com/m3db/m3/src/m3ninx/postings"
26+
)
27+
28+
type documentIterator struct {
29+
retriever DocRetriever
30+
postingsIter postings.Iterator
31+
32+
currDoc doc.Document
33+
currID postings.ID
34+
closed bool
35+
err error
36+
}
37+
38+
// NewIterator returns a new Iterator
39+
func NewIterator(r DocRetriever, pi postings.Iterator) doc.Iterator {
40+
return &documentIterator{
41+
retriever: r,
42+
postingsIter: pi,
43+
}
44+
}
45+
46+
func (e *documentIterator) Next() bool {
47+
if e.closed || e.err != nil || !e.postingsIter.Next() {
48+
return false
49+
}
50+
id := e.postingsIter.Current()
51+
e.currID = id
52+
53+
d, err := e.retriever.Doc(id)
54+
if err != nil {
55+
e.err = err
56+
return false
57+
}
58+
e.currDoc = d
59+
return true
60+
}
61+
62+
func (e *documentIterator) Current() doc.Document {
63+
return e.currDoc
64+
}
65+
66+
func (e *documentIterator) Err() error {
67+
return e.err
68+
}
69+
70+
func (e *documentIterator) Close() error {
71+
if e.closed {
72+
return errIteratorClosed
73+
}
74+
e.closed = true
75+
e.currDoc = doc.Document{}
76+
e.currID = postings.ID(0)
77+
err := e.postingsIter.Close()
78+
return err
79+
}

src/m3ninx/index/iterator_test.go

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2021 Uber Technologies, Inc.
2+
//
3+
// Permission is hereby granted, free of charge, to any person obtaining a copy
4+
// of this software and associated documentation files (the "Software"), to deal
5+
// in the Software without restriction, including without limitation the rights
6+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
// copies of the Software, and to permit persons to whom the Software is
8+
// furnished to do so, subject to the following conditions:
9+
//
10+
// The above copyright notice and this permission notice shall be included in
11+
// all copies or substantial portions of the Software.
12+
//
13+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
// THE SOFTWARE.
20+
21+
package index
22+
23+
import (
24+
"testing"
25+
26+
"github.com/m3db/m3/src/m3ninx/doc"
27+
"github.com/m3db/m3/src/m3ninx/index/segment/fst/encoding"
28+
"github.com/m3db/m3/src/m3ninx/postings"
29+
xtest "github.com/m3db/m3/src/x/test"
30+
31+
"github.com/golang/mock/gomock"
32+
"github.com/stretchr/testify/require"
33+
)
34+
35+
func TestDocIterator(t *testing.T) {
36+
mockCtrl := xtest.NewController(t)
37+
defer mockCtrl.Finish()
38+
39+
docs := []doc.Metadata{
40+
{
41+
ID: []byte("doc-id-1"),
42+
Fields: []doc.Field{
43+
{
44+
Name: []byte("apple"),
45+
Value: []byte("red"),
46+
},
47+
},
48+
},
49+
{
50+
ID: []byte("doc-id-2"),
51+
Fields: []doc.Field{
52+
{
53+
Name: []byte("banana"),
54+
Value: []byte("yellow"),
55+
},
56+
},
57+
},
58+
}
59+
60+
encodedDocsWithIds := make([]docsWithIDs, 0, len(docs))
61+
for i, d := range docs {
62+
encodedDocsWithIds = append(encodedDocsWithIds, docsWithIDs{
63+
id: postings.ID(i),
64+
doc: doc.NewDocumentFromEncoded(
65+
doc.Encoded{Bytes: docToBytes(d)}),
66+
})
67+
}
68+
69+
retriever := NewMockDocRetriever(mockCtrl)
70+
gomock.InOrder(
71+
retriever.EXPECT().Doc(encodedDocsWithIds[0].id).Return(encodedDocsWithIds[0].doc, nil),
72+
retriever.EXPECT().Doc(encodedDocsWithIds[1].id).Return(encodedDocsWithIds[1].doc, nil),
73+
)
74+
75+
postingsIter := postings.NewMockIterator(mockCtrl)
76+
gomock.InOrder(
77+
postingsIter.EXPECT().Next().Return(true),
78+
postingsIter.EXPECT().Current().Return(encodedDocsWithIds[0].id),
79+
postingsIter.EXPECT().Next().Return(true),
80+
postingsIter.EXPECT().Current().Return(encodedDocsWithIds[1].id),
81+
postingsIter.EXPECT().Next().Return(false),
82+
postingsIter.EXPECT().Close().Return(nil),
83+
)
84+
85+
it := NewIterator(retriever, postingsIter)
86+
87+
require.True(t, it.Next())
88+
require.Equal(t, encodedDocsWithIds[0].doc, it.Current())
89+
require.True(t, it.Next())
90+
require.Equal(t, encodedDocsWithIds[1].doc, it.Current())
91+
require.False(t, it.Next())
92+
require.NoError(t, it.Err())
93+
94+
require.NoError(t, it.Close())
95+
}
96+
97+
type docsWithIDs struct {
98+
id postings.ID
99+
doc doc.Document
100+
}
101+
102+
func docToBytes(d doc.Metadata) []byte {
103+
enc := encoding.NewEncoder(1024)
104+
n := enc.PutBytes(d.ID)
105+
n += enc.PutUvarint(uint64(len(d.Fields)))
106+
for _, f := range d.Fields { // nolint:gocritic
107+
n += enc.PutBytes(f.Name)
108+
n += enc.PutBytes(f.Value)
109+
}
110+
111+
return enc.Bytes()
112+
}

src/m3ninx/index/metadata_iterator.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030
var errIteratorClosed = errors.New("iterator has been closed")
3131

3232
type idDocIterator struct {
33-
retriever DocRetriever
33+
retriever MetadataRetriever
3434
postingsIter postings.Iterator
3535

3636
currDoc doc.Metadata
@@ -40,7 +40,7 @@ type idDocIterator struct {
4040
}
4141

4242
// NewIDDocIterator returns a new NewIDDocIterator.
43-
func NewIDDocIterator(r DocRetriever, pi postings.Iterator) IDDocIterator {
43+
func NewIDDocIterator(r MetadataRetriever, pi postings.Iterator) IDDocIterator {
4444
return &idDocIterator{
4545
retriever: r,
4646
postingsIter: pi,
@@ -54,7 +54,7 @@ func (it *idDocIterator) Next() bool {
5454
id := it.postingsIter.Current()
5555
it.currID = id
5656

57-
d, err := it.retriever.Doc(id)
57+
d, err := it.retriever.Metadata(id)
5858
if err != nil {
5959
it.err = err
6060
return false

0 commit comments

Comments
 (0)