@@ -50,6 +50,7 @@ type IndexSnapshotTermFieldReader struct {
5050 recycle bool
5151 bytesRead uint64
5252 ctx context.Context
53+ unadorned bool
5354}
5455
5556func (i * IndexSnapshotTermFieldReader ) incrementBytesRead (val uint64 ) {
@@ -146,14 +147,31 @@ func (i *IndexSnapshotTermFieldReader) Advance(ID index.IndexInternalID, preAllo
146147 // FIXME do something better
147148 // for now, if we need to seek backwards, then restart from the beginning
148149 if i .currPosting != nil && bytes .Compare (i .currID , ID ) >= 0 {
149- i2 , err := i .snapshot .TermFieldReader (nil , i .term , i .field ,
150- i .includeFreq , i .includeNorm , i .includeTermVectors )
151- if err != nil {
152- return nil , err
150+ // Check if the TFR is a special unadorned composite optimization.
151+ // Such a TFR will NOT have a valid `term` or `field` set, making it
152+ // impossible for the TFR to replace itself with a new one.
153+ if ! i .unadorned {
154+ i2 , err := i .snapshot .TermFieldReader (nil , i .term , i .field ,
155+ i .includeFreq , i .includeNorm , i .includeTermVectors )
156+ if err != nil {
157+ return nil , err
158+ }
159+ // close the current term field reader before replacing it with a new one
160+ _ = i .Close ()
161+ * i = * (i2 .(* IndexSnapshotTermFieldReader ))
162+ } else {
163+ // unadorned composite optimization
164+ // we need to reset all the iterators
165+ // back to the beginning, which effectively
166+ // achives the same thing as the above
167+ for _ , iter := range i .iterators {
168+ optimizedIterator , ok := iter .(* unadornedPostingsIteratorBitmap )
169+ if ! ok {
170+ return nil , fmt .Errorf ("unexpected iterator type %T" , iter )
171+ }
172+ optimizedIterator .ResetIterator ()
173+ }
153174 }
154- // close the current term field reader before replacing it with a new one
155- _ = i .Close ()
156- * i = * (i2 .(* IndexSnapshotTermFieldReader ))
157175 }
158176 num , err := docInternalToNumber (ID )
159177 if err != nil {
0 commit comments