github.com/m3db/m3@v1.5.0/src/m3ninx/index/segment/mem/reader.go (about) 1 // Copyright (c) 2018 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 mem 22 23 import ( 24 "errors" 25 "sync" 26 27 "github.com/m3db/m3/src/m3ninx/doc" 28 "github.com/m3db/m3/src/m3ninx/index" 29 sgmt "github.com/m3db/m3/src/m3ninx/index/segment" 30 "github.com/m3db/m3/src/m3ninx/postings" 31 ) 32 33 var ( 34 errSegmentReaderClosed = errors.New("segment reader is closed") 35 errReaderNilRegex = errors.New("nil regex received") 36 ) 37 38 type reader struct { 39 sync.RWMutex 40 41 segment ReadableSegment 42 limits readerDocRange 43 plPool postings.Pool 44 45 closed bool 46 } 47 48 type readerDocRange struct { 49 startInclusive postings.ID 50 endExclusive postings.ID 51 } 52 53 func newReader(s ReadableSegment, l readerDocRange, p postings.Pool) sgmt.Reader { 54 return &reader{ 55 segment: s, 56 limits: l, 57 plPool: p, 58 } 59 } 60 61 func (r *reader) Fields() (sgmt.FieldsIterator, error) { 62 return r.segment.Fields() 63 } 64 65 func (r *reader) ContainsField(field []byte) (bool, error) { 66 return r.segment.ContainsField(field) 67 } 68 69 func (r *reader) Terms(field []byte) (sgmt.TermsIterator, error) { 70 return r.segment.Terms(field) 71 } 72 73 func (r *reader) FieldsPostingsList() (sgmt.FieldsPostingsListIterator, error) { 74 return r.segment.FieldsPostingsList() 75 } 76 77 func (r *reader) MatchField(field []byte) (postings.List, error) { 78 // falling back to regexp .* as this segment implementation is only used in tests. 79 return r.MatchRegexp(field, index.DotStarCompiledRegex()) 80 } 81 82 func (r *reader) MatchTerm(field, term []byte) (postings.List, error) { 83 r.RLock() 84 defer r.RUnlock() 85 if r.closed { 86 return nil, errSegmentReaderClosed 87 } 88 89 // A reader can return IDs in the posting list which are greater than its limit. 90 // The reader only guarantees that when fetching the documents associated with a 91 // postings list through a call to Docs, IDs greater than or equal to the limit 92 // will be filtered out. 93 pl, err := r.segment.matchTerm(field, term) 94 return pl, err 95 } 96 97 func (r *reader) MatchRegexp(field []byte, compiled index.CompiledRegex) (postings.List, error) { 98 r.RLock() 99 defer r.RUnlock() 100 if r.closed { 101 return nil, errSegmentReaderClosed 102 } 103 104 // A reader can return IDs in the posting list which are greater than its maximum 105 // permitted ID. The reader only guarantees that when fetching the documents associated 106 // with a postings list through a call to Docs will IDs greater than the maximum be 107 // filtered out. 108 compileRE := compiled.Simple 109 if compileRE == nil { 110 return nil, errReaderNilRegex 111 } 112 113 return r.segment.matchRegexp(field, compileRE) 114 } 115 116 func (r *reader) MatchAll() (postings.List, error) { 117 r.RLock() 118 defer r.RUnlock() 119 if r.closed { 120 return nil, errSegmentReaderClosed 121 } 122 123 pl := r.plPool.Get() 124 err := pl.AddRange(r.limits.startInclusive, r.limits.endExclusive) 125 if err != nil { 126 return nil, err 127 } 128 return pl, nil 129 } 130 131 func (r *reader) Metadata(id postings.ID) (doc.Metadata, error) { 132 r.RLock() 133 defer r.RUnlock() 134 135 return r.getMetadataWithRLock(id) 136 } 137 138 func (r *reader) MetadataIterator(pl postings.List) (doc.MetadataIterator, error) { 139 r.RLock() 140 defer r.RUnlock() 141 if r.closed { 142 return nil, errSegmentReaderClosed 143 } 144 boundedIter := newBoundedPostingsIterator(pl.Iterator(), r.limits) 145 return r.getMetadataIterWithLock(boundedIter), nil 146 } 147 148 func (r *reader) Doc(id postings.ID) (doc.Document, error) { 149 r.RLock() 150 defer r.RUnlock() 151 152 m, err := r.getMetadataWithRLock(id) 153 if err != nil { 154 return doc.Document{}, err 155 } 156 157 return doc.NewDocumentFromMetadata(m), nil 158 } 159 160 func (r *reader) Docs(pl postings.List) (doc.Iterator, error) { 161 r.RLock() 162 defer r.RUnlock() 163 164 if r.closed { 165 return nil, errSegmentReaderClosed 166 } 167 168 boundedIter := newBoundedPostingsIterator(pl.Iterator(), r.limits) 169 return index.NewIterator(r, boundedIter), nil 170 } 171 172 func (r *reader) AllDocs() (index.IDDocIterator, error) { 173 r.RLock() 174 defer r.RUnlock() 175 if r.closed { 176 return nil, errSegmentReaderClosed 177 } 178 179 pi := postings.NewRangeIterator(r.limits.startInclusive, r.limits.endExclusive) 180 return r.getMetadataIterWithLock(pi), nil 181 } 182 183 func (r *reader) getMetadataIterWithLock(iter postings.Iterator) index.IDDocIterator { 184 return index.NewIDDocIterator(r, iter) 185 } 186 187 func (r *reader) getMetadataWithRLock(id postings.ID) (doc.Metadata, error) { 188 if r.closed { 189 return doc.Metadata{}, errSegmentReaderClosed 190 } 191 192 if id < r.limits.startInclusive || id >= r.limits.endExclusive { 193 return doc.Metadata{}, index.ErrDocNotFound 194 } 195 196 return r.segment.getDoc(id) 197 } 198 199 func (r *reader) Close() error { 200 r.Lock() 201 if r.closed { 202 r.Unlock() 203 return errSegmentReaderClosed 204 } 205 r.closed = true 206 r.Unlock() 207 return nil 208 }