github.com/m3db/m3@v1.5.0/src/dbnode/encoding/multi_reader_iterator.go (about)

     1  // Copyright (c) 2016 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 encoding
    22  
    23  import (
    24  	"errors"
    25  	"time"
    26  
    27  	"github.com/m3db/m3/src/dbnode/namespace"
    28  	"github.com/m3db/m3/src/dbnode/ts"
    29  	"github.com/m3db/m3/src/dbnode/x/xio"
    30  	xtime "github.com/m3db/m3/src/x/time"
    31  )
    32  
    33  var (
    34  	errOutOfOrderIterator = errors.New("values are out of order from inner iterator")
    35  )
    36  
    37  // multiReaderIterator is an iterator that iterates in order over a list of sets of
    38  // internally ordered but not collectively in order readers, it also deduplicates datapoints.
    39  type multiReaderIterator struct {
    40  	schemaDesc       namespace.SchemaDescr
    41  	iters            iterators
    42  	slicesIter       xio.ReaderSliceOfSlicesIterator
    43  	iteratorAlloc    ReaderIteratorAllocate
    44  	singleSlicesIter singleSlicesOfSlicesIterator
    45  	pool             MultiReaderIteratorPool
    46  	err              error
    47  	firstNext        bool
    48  	closed           bool
    49  }
    50  
    51  // NewMultiReaderIterator creates a new multi-reader iterator.
    52  func NewMultiReaderIterator(
    53  	iteratorAlloc ReaderIteratorAllocate,
    54  	pool MultiReaderIteratorPool,
    55  ) MultiReaderIterator {
    56  	it := &multiReaderIterator{pool: pool, iteratorAlloc: iteratorAlloc}
    57  	it.iters.closeIters = true
    58  	it.Reset(nil, 0, 0, nil)
    59  	return it
    60  }
    61  
    62  func (it *multiReaderIterator) Next() bool {
    63  	if !it.firstNext {
    64  		// When firstNext do not progress the first time
    65  		if !it.hasNext() {
    66  			return false
    67  		}
    68  		it.moveToNext()
    69  	}
    70  	it.firstNext = false
    71  	return it.hasNext()
    72  }
    73  
    74  func (it *multiReaderIterator) Current() (ts.Datapoint, xtime.Unit, ts.Annotation) {
    75  	return it.iters.current()
    76  }
    77  
    78  func (it *multiReaderIterator) hasError() bool {
    79  	return it.err != nil
    80  }
    81  
    82  func (it *multiReaderIterator) isClosed() bool {
    83  	return it.closed
    84  }
    85  
    86  func (it *multiReaderIterator) hasMore() bool {
    87  	return it.iters.len() > 0 || it.slicesIter != nil
    88  }
    89  
    90  func (it *multiReaderIterator) hasNext() bool {
    91  	return !it.hasError() && !it.isClosed() && it.hasMore()
    92  }
    93  
    94  func (it *multiReaderIterator) moveToNext() {
    95  	if it.iters.len() > 0 {
    96  		it.moveIteratorsToNext()
    97  	}
    98  	if it.iters.len() > 0 || it.hasError() {
    99  		// Still have valid iters or has error
   100  		return
   101  	}
   102  
   103  	// Move forward through slices of readers
   104  	if !it.slicesIter.Next() {
   105  		// No more readers, nil out so that hasMore reflects correctly
   106  		it.slicesIter.Close()
   107  		it.slicesIter = nil
   108  		return
   109  	}
   110  
   111  	// Add all readers to current iterators heap
   112  	currentLen, _, _ := it.slicesIter.CurrentReaders()
   113  	for i := 0; i < currentLen; i++ {
   114  		var (
   115  			reader = it.slicesIter.CurrentReaderAt(i)
   116  			iter   = it.iteratorAlloc(reader, it.schemaDesc)
   117  		)
   118  		if iter.Next() {
   119  			// Only insert it if it has values
   120  			it.iters.push(iter)
   121  		} else {
   122  			err := iter.Err()
   123  			iter.Close()
   124  			if it.err == nil && err != nil {
   125  				it.err = err
   126  			}
   127  		}
   128  	}
   129  
   130  	if it.iters.len() == 0 && !it.hasError() {
   131  		// No iterators were added, move to next
   132  		it.moveToNext()
   133  	}
   134  }
   135  
   136  func (it *multiReaderIterator) moveIteratorsToNext() {
   137  	for {
   138  		prev := it.iters.at()
   139  		next, err := it.iters.moveToValidNext()
   140  		if it.err == nil && err != nil {
   141  			it.err = err
   142  			return
   143  		}
   144  		if err != nil || !next {
   145  			return
   146  		}
   147  
   148  		curr := it.iters.at()
   149  		if curr != prev {
   150  			return
   151  		}
   152  
   153  		// Dedupe by continuing
   154  	}
   155  }
   156  
   157  func (it *multiReaderIterator) Err() error {
   158  	return it.err
   159  }
   160  
   161  func (it *multiReaderIterator) Readers() xio.ReaderSliceOfSlicesIterator {
   162  	return it.slicesIter
   163  }
   164  
   165  func (it *multiReaderIterator) Reset(
   166  	blocks []xio.SegmentReader,
   167  	start xtime.UnixNano,
   168  	blockSize time.Duration,
   169  	descr namespace.SchemaDescr,
   170  ) {
   171  	it.singleSlicesIter.readers = blocks
   172  	it.singleSlicesIter.firstNext = true
   173  	it.singleSlicesIter.closed = false
   174  	it.singleSlicesIter.start = start
   175  	it.singleSlicesIter.blockSize = blockSize
   176  	it.ResetSliceOfSlices(&it.singleSlicesIter, descr)
   177  }
   178  
   179  func (it *multiReaderIterator) ResetSliceOfSlices(slicesIter xio.ReaderSliceOfSlicesIterator, descr namespace.SchemaDescr) {
   180  	it.schemaDesc = descr
   181  	it.iters.reset()
   182  	it.slicesIter = slicesIter
   183  	it.err = nil
   184  	it.firstNext = true
   185  	it.closed = false
   186  	// Try moveToNext to load values for calls to Current before Next
   187  	it.moveToNext()
   188  }
   189  
   190  func (it *multiReaderIterator) Schema() namespace.SchemaDescr {
   191  	return it.schemaDesc
   192  }
   193  
   194  func (it *multiReaderIterator) Close() {
   195  	if it.isClosed() {
   196  		return
   197  	}
   198  	it.closed = true
   199  	it.iters.reset()
   200  	if it.slicesIter != nil {
   201  		it.slicesIter.Close()
   202  	}
   203  	it.slicesIter = nil
   204  	if it.pool != nil {
   205  		it.pool.Put(it)
   206  	}
   207  }
   208  
   209  type singleSlicesOfSlicesIterator struct {
   210  	readers   []xio.SegmentReader
   211  	firstNext bool
   212  	closed    bool
   213  	start     xtime.UnixNano
   214  	blockSize time.Duration
   215  }
   216  
   217  func (it *singleSlicesOfSlicesIterator) Next() bool {
   218  	if !it.firstNext || it.closed {
   219  		return false
   220  	}
   221  	it.firstNext = false
   222  	return true
   223  }
   224  
   225  func (it *singleSlicesOfSlicesIterator) CurrentReaders() (int, xtime.UnixNano, time.Duration) {
   226  	return len(it.readers), it.start, it.blockSize
   227  }
   228  
   229  func (it *singleSlicesOfSlicesIterator) CurrentReaderAt(idx int) xio.BlockReader {
   230  	return xio.BlockReader{
   231  		SegmentReader: it.readers[idx],
   232  		Start:         it.start,
   233  		BlockSize:     it.blockSize,
   234  	}
   235  }
   236  
   237  func (it *singleSlicesOfSlicesIterator) Close() {
   238  	if it.closed {
   239  		return
   240  	}
   241  	it.closed = true
   242  }
   243  
   244  func (it *singleSlicesOfSlicesIterator) Size() (int, error) {
   245  	size := 0
   246  	for _, reader := range it.readers {
   247  		seg, err := reader.Segment()
   248  		if err != nil {
   249  			return 0, err
   250  		}
   251  		size += seg.Len()
   252  	}
   253  	return size, nil
   254  }
   255  
   256  func (it *singleSlicesOfSlicesIterator) RewindToIndex(idx int) {
   257  	it.firstNext = idx <= 0
   258  }
   259  
   260  func (it *singleSlicesOfSlicesIterator) Index() int {
   261  	if it.firstNext {
   262  		return 0
   263  	}
   264  	return 1
   265  }